「ZJOI2018」历史(LCT)

「ZJOI2018」历史(LCT)

\(ZJOI\) 也就数据结构可做了……

题意:给定每个点 \(access\) 次数,使轻重链切换次数最大,带修改。

\(30pts:\)

挺好想的。发现切换次数只跟子树中所有结点的 \(access\) 次数,可以树形 \(dp\)。假设 \(x\)\(m\) 个儿子,每个儿子的 \(access\) 次数为 \(A_i\),自己为 \(A_0\),问题转换成有 \(m+1\) 种颜色,问怎么使颜色不同的间隔最多。使 \(sum=\sum_{i=0}^{m}A_i,val=\max_{i=0}^{m}A_i\),那么答案为 \(\min(sum-1,2\times (sum-val))\)

那么我们把 \(\min\) 拆开,当 \(2\times val>sum\) 时,\(2\times (sum-val)\) 更小,否则 \(sum-1\) 更小。

然后就可以 \(O(n)\) 预处理了。

\(100pts:\)

考虑怎么带修改。

我们暴力跳肯定不行,那可以用 \(LCT\) 模拟这个暴力跳的过程。时间复杂度 \(O(n\log n)\)

\(Code\ below:\)

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=400000+10;
int n,m,son[maxn],op[maxn];
int ch[maxn][2],fa[maxn];ll w[maxn],sum[maxn],siz[maxn],ans;
int head[maxn],to[maxn<<1],nxt[maxn<<1],tot;

inline int read(){
	register int x=0,f=1;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
	while(isdigit(ch)){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
	return (f==1)?x:-x;
}
void print(ll x){
	if(x<0){putchar('-');x=-x;}
	if(x>9) print(x/10);
	putchar(x%10+'0');
}

inline void pushup(int x){
	sum[x]=sum[ch[x][0]]+sum[ch[x][1]]+siz[x]+w[x];
}
inline bool nrt(int x){
	return ch[fa[x]][0]==x||ch[fa[x]][1]==x;
}
inline void rotate(int x){
	int y=fa[x],z=fa[y],k=(ch[y][1]==x),u=ch[x][k^1];
	if(nrt(y)) ch[z][ch[z][1]==y]=x;
	ch[y][k]=u;ch[x][k^1]=y;
	if(u) fa[u]=y;fa[y]=x;fa[x]=z;
	pushup(y);pushup(x);
}
inline void splay(int x){
	int y,z;
	while(nrt(x)){
		y=fa[x],z=fa[y];
		if(nrt(y)) rotate((ch[y][1]==x)^(ch[z][1]==y)?x:y);
		rotate(x);
	}
}

inline void addedge(int x,int y){
	to[++tot]=y;
	nxt[tot]=head[x];
	head[x]=tot;
}

void dfs(int x,int f){
	fa[x]=f;
	ll maxson=-1;
	for(int i=head[x],y;i;i=nxt[i]){
		y=to[i];
		if(y==f) continue;
		dfs(y,x);siz[x]+=sum[y];
		if(sum[y]>maxson) maxson=sum[y],son[x]=y;
	}
	sum[x]=siz[x]+w[x];
	if((maxson<<1)>sum[x]){
		op[x]=0;ans+=(sum[x]-maxson)<<1;
		ch[x][1]=son[x];siz[x]-=maxson;
	}
	else if((w[x]<<1)>sum[x]) op[x]=1,ans+=(sum[x]-w[x])<<1;
	else op[x]=2,ans+=sum[x]-1;
}

inline void modify(int x,int z){
	ll S;
	for(int y=0;x;y=x,x=fa[x]){
		splay(x);S=sum[x]-sum[ch[x][0]];
		ans-=(op[x]<2)?(S-(op[x]?w[x]:sum[ch[x][1]]))<<1:S-1;
		S+=z;sum[x]+=z;y?siz[x]+=z:w[x]+=z;
		if((sum[y]<<1)>S) siz[x]+=sum[ch[x][1]]-sum[y],ch[x][1]=y;
		if((sum[ch[x][1]]<<1)>S) op[x]=0,ans+=(S-sum[ch[x][1]])<<1;
		else {
			if(ch[x][1]) siz[x]+=sum[ch[x][1]],ch[x][1]=0;
			if((w[x]<<1)>S) op[x]=1,ans+=(S-w[x])<<1;
			else op[x]=2,ans+=S-1;
		}
	}
}

int main()
{
	n=read(),m=read();
	int x,y;
	for(int i=1;i<=n;i++) w[i]=read();
	for(int i=1;i<n;i++){
		x=read(),y=read();
		addedge(x,y),addedge(y,x);
	}
	dfs(1,0);
	print(ans),putchar('\n');
	for(int i=1;i<=m;i++){
		x=read(),y=read();modify(x,y);
		print(ans),putchar('\n');
	}
	return 0;
}
posted @ 2019-03-13 08:54  Owen_codeisking  阅读(417)  评论(0编辑  收藏  举报