【BZOJ5212】[ZJOI2018]历史(Link-Cut Tree)
【BZOJ5212】[ZJOI2018]历史(Link-Cut Tree)
题面
题解
显然实际上就是给定了一棵树和每个点被\(access\)的次数,求解轻重链切换的最大次数。
先考虑不带修改的答案。
如果直接考虑全局的答案会很麻烦。
考虑每一个在每一个点处被切换的次数。
显然这个子树之和其子树内的点的\(access\)次数相关,和子树外的点无关。
而在这个点处被切换只有它的子树中不在同一棵子树内的两个点先后进行\(access\)。
对于一个点统计其不同子树内的\(access\)次数和,那么对于当前点而言,等价于有子树个数种颜色,每种颜色可以使用若干次,求一个放置方案数,使得相邻颜色不同的组数最多。
这个东西貌似是场\(agc\)的\(a\)题????
假设颜色总和是\(s\),最大值为\(p\),那么答案就是\(min\{s-1,2*(s-p)\}\)
原因大概就是看看出现次数最多的那个多不多,如果不是很多的话就可以穿插的放。(强行解释.jpg)
那么这样子可以进行一次\(dfs\),\(O(n)\)的算出答案。
然后现在存在了修改操作。
首先发现这个东西是一个加法操作,然后发现会影响的只有到达根的这一段路径。
那么考虑一下\(s-1<2*(s-p)\)推出来是\(2p<s+1\)。
而这样一次操作之后,路径上的\(s\)会做加法,而\(p\)呢????
来一点骚操作,我们对于\(2s_v\le s_u+1\)的、存在父子关系的两个点\(u,v\)之间连上一条轻边,在\(2s_v>s_u+1\)的\(u,v\)之间连上一条重边。
然后我们似乎就完成了一次重链剖分,可以证明每个点只会拥有不超过一个重儿子。
那么也可以发现到根节点的轻边数量是\(log\)级别的。
继续看看,发现进行区间加法的时候,重儿子显然还是满足上述条件,直接跳过不需要考虑。
那么对于一个轻儿子特殊的考虑一下是否需要修改其状态。
那么动态的修改轻重儿子就是\(LCT\)可以完成的事情啦。
#include<iostream>
#include<cstdio>
using namespace std;
#define ll long long
#define MAX 400400
inline int read()
{
int x=0;bool t=false;char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
if(ch=='-')t=true,ch=getchar();
while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
return t?-x:x;
}
struct Line{int v,next;}e[MAX<<1];
int h[MAX],cnt=1;
inline void Add(int u,int v){e[cnt]=(Line){v,h[u]};h[u]=cnt++;}
int n,m,hson[MAX];
ll a[MAX],s[MAX],ss[MAX],ans;
struct Node{int ch[2],ff;}t[MAX];
bool isroot(int x){return t[t[x].ff].ch[0]!=x&&t[t[x].ff].ch[1]!=x;}
void pushup(int x){s[x]=s[t[x].ch[0]]+s[t[x].ch[1]]+ss[x]+a[x];}
void rotate(int x)
{
int y=t[x].ff,z=t[y].ff;
int k=t[y].ch[1]==x;
if(!isroot(y))t[z].ch[t[z].ch[1]==y]=x;t[x].ff=z;
t[y].ch[k]=t[x].ch[k^1];t[t[x].ch[k^1]].ff=y;
t[x].ch[k^1]=y;t[y].ff=x;
pushup(y);pushup(x);
}
void Splay(int x)
{
while(!isroot(x))
{
int y=t[x].ff,z=t[y].ff;
if(!isroot(y))
(t[y].ch[0]==x)^(t[z].ch[0]==y)?rotate(x):rotate(y);
rotate(x);
}
}
void dfs(int u,int ff)
{
ll mx=a[u];int ms=u;s[u]=a[u];t[u].ff=ff;
for(int i=h[u];i;i=e[i].next)
if(e[i].v!=ff)
{
dfs(e[i].v,u),s[u]+=s[e[i].v];
if(s[e[i].v]>mx)mx=s[e[i].v],ms=e[i].v;
}
ss[u]=s[u]-a[u];
if(2*mx>s[u])
{
ans+=(s[u]-mx)*2;
if(ms==u)hson[u]=0;
else hson[u]=1,t[u].ch[1]=ms,ss[u]-=mx;
}
else ans+=s[u]-1,hson[u]=2;
}
int main()
{
n=read();m=read();
for(int i=1;i<=n;++i)a[i]=read();
for(int i=1;i<n;++i)
{
int u=read(),v=read();
Add(u,v);Add(v,u);
}
dfs(1,0);printf("%lld\n",ans);
while(m--)
{
int x=read(),w=read();
for(int y=0;x;y=x,x=t[x].ff)
{
Splay(x);
ll S=s[x]-s[t[x].ch[0]];
if(hson[x]==0)ans-=(S-a[x])*2;
if(hson[x]==1)ans-=(S-s[t[x].ch[1]])*2;
if(hson[x]==2)ans-=S-1;
S+=w;s[x]+=w;if(y)ss[x]+=w;else a[x]+=w;
if(s[y]*2>S)ss[x]+=s[t[x].ch[1]],ss[x]-=s[y],t[x].ch[1]=y;
if(s[t[x].ch[1]]*2>S)hson[x]=1,ans+=(S-s[t[x].ch[1]])*2;
else
{
if(t[x].ch[1])ss[x]+=s[t[x].ch[1]],t[x].ch[1]=0;
if(a[x]*2>S)hson[x]=0,ans+=(S-a[x])*2;
else hson[x]=2,ans+=S-1,t[x].ch[1]=0;
}
}
printf("%lld\n",ans);
}
return 0;
}
【BZOJ5212】[ZJOI2018]历史(Link-Cut Tree)的更多相关文章
- link cut tree 入门
鉴于最近写bzoj还有51nod都出现写不动的现象,决定学习一波厉害的算法/数据结构. link cut tree:研究popoqqq那个神ppt. bzoj1036:维护access操作就可以了. ...
- Codeforces Round #339 (Div. 2) A. Link/Cut Tree 水题
A. Link/Cut Tree 题目连接: http://www.codeforces.com/contest/614/problem/A Description Programmer Rostis ...
- Link/cut Tree
Link/cut Tree 一棵link/cut tree是一种用以表示一个森林,一个有根树集合的数据结构.它提供以下操作: 向森林中加入一棵只有一个点的树. 将一个点及其子树从其所在的树上断开. 将 ...
- 洛谷P3690 Link Cut Tree (模板)
Link Cut Tree 刚开始写了个指针版..调了一天然后放弃了.. 最后还是学了黄学长的板子!! #include <bits/stdc++.h> #define INF 0x3f3 ...
- LCT总结——概念篇+洛谷P3690[模板]Link Cut Tree(动态树)(LCT,Splay)
为了优化体验(其实是强迫症),蒟蒻把总结拆成了两篇,方便不同学习阶段的Dalao们切换. LCT总结--应用篇戳这里 概念.性质简述 首先介绍一下链剖分的概念(感谢laofu的讲课) 链剖分,是指一类 ...
- bzoj2049 [Sdoi2008]Cave 洞穴勘测 link cut tree入门
link cut tree入门题 首先说明本人只会写自底向上的数组版(都说了不写指针.不写自顶向下QAQ……) 突然发现link cut tree不难写... 说一下各个函数作用: bool isro ...
- P3690 【模板】Link Cut Tree (动态树)
P3690 [模板]Link Cut Tree (动态树) 认父不认子的lct 注意:不 要 把 $fa[x]$和$nrt(x)$ 混 在 一 起 ! #include<cstdio> v ...
- Link Cut Tree学习笔记
从这里开始 动态树问题和Link Cut Tree 一些定义 access操作 换根操作 link和cut操作 时间复杂度证明 Link Cut Tree维护链上信息 Link Cut Tree维护子 ...
- [CodeForces - 614A] A - Link/Cut Tree
A - Link/Cut Tree Programmer Rostislav got seriously interested in the Link/Cut Tree data structure, ...
随机推荐
- 软件工程(FZU2015) 赛季得分榜,第七回合
SE_FZU目录:1 2 3 4 5 6 7 8 9 10 11 12 13 积分规则 积分制: 作业为10分制,练习为3分制:alpha30分: 团队项目分=团队得分+个人贡献分 个人贡献分: 个人 ...
- JMeter学习FTP测试计划(转)
FTP服务主要提供上传和下载功能.有时间需要我们测试服务器上传和下载的性能.在这里我通过JMeter做一个FTP测试计划的例子. 1.创建一个线程组 2.线程组--->添加--->配置元件 ...
- [转帖]2015年时微软Win3.1崩溃迫使巴黎奥利机场短暂关闭
https://www.ithome.com/html/it/188796.htm IT之家讯 2015年11月14日消息,上周法国巴黎奥利机场因为微软的Windows 3.1系统出现故障不得不迫使所 ...
- Oracle列转行函数LISTAGG()
--Oracle列转行函数LISTAGG() with tb_temp as( select 'China' 国家,'Wuhan' 城市 from dual union all select 'Chi ...
- Freemarker 页面静态化技术使用入门案例
在访问 新闻.活动.商品 详情页面时, 路径可以是 xx[id].html, 服务器端根据请求 id, 动态生成 html 网页,下次访问数据时,无需再查询数据,直接将 html 静态页面返回.这样一 ...
- php变量详解
变量是用于存储信息的"容器". 定义一个变量的语法: $变量名 = 值; 使用变量的例子: <?php $x=5; $y=6; $z=$x+$y; echo $z; ?> ...
- Spring-Boot Banner
下载Spring-Boot源码,目录结构spring-boot-2.1.0.M2\spring-boot-2.1.0.M2\spring-boot-project\spring-boot\src\ma ...
- js中的call、apply、bind
在js中每个函数都包含两个非继承而来的方法:call()和apply() call和apply的作用都是在特定的作用域中将函数绑定到另外一个对象上去运行,即可以用来重新定义函数的执行环境,两者仅在定义 ...
- mongodb的安装方法
下载安装 mongodb官网下载地址:https://www.mongodb.org/downloads#produc...直接下载.msi文件并安装到指定目录即可.我的安装路径是D:\mongodb ...
- java.lang.NoClassDefFoundError: org/apache/log4j/Priority的问题解决
在pom 文件中添加 <dependency> <groupId>log4j</groupId> <artifactId>log4j</artif ...