P4115 Qtree4

链接

写一个 \(LCT\) 做法。

对于一个以 \(x\) 为根的 \(splay\) ,设 \(mx_x\) 为以 \(x\) 为根的子树中的答案,显然可以与 \(ls_x,rs_x\) 与虚子树中的 \(mx\) 取最大值。

显然只有经过 \(x\) 的链没有计算,我们考虑 \(x\) 本身,\(ls_x,rs_x\) 和虚子树中白点离 \(x\) 最远的距离,它们中任意两个相加都可以更新答案,以及虚子树中的最长链与次长链相加也可以更新答案。

如何维护它们呢?设 \(lx_x\) 为以 \(x\) 为根的 \(splay\) 中白点离最左端的点的最长距离,\(ls_x\) 中白点离 \(x\) 最远的距离即可通过 \(rx_{ls_x}\) 得出,\(rx_x\) 同理。

\(lx_x\) 可以由 \(lx_{ls_x}\)\(lx_{rs_x}\) 与虚子树最长链加上左部分的边的总权值得到,\(rx_x\) 同理。

边权可以拆边或直接赋到点上维护,这里用第二种方法,常数小,但边权处理稍显复杂。

\(\frak{code}\)

#include<bits/stdc++.h>
#define IL inline
#define LL long long
#define ls(x) ch[x][0]
#define rs(x) ch[x][1]
using namespace std;
const int N=1e5+3,inf=1e9;
struct hh{
	int to,nxt,w;
}e[N<<1];
int n,m,num,siz,ans,val[N],col[N],fir[N];
int fa[N],ch[N][2],vsum[N],lx[N],rx[N],mx[N],lv[N];
IL int in(){
	char c;int f=1;
	while((c=getchar())<'0'||c>'9')
	  if(c=='-') f=-1;
	int x=c-'0';
	while((c=getchar())>='0'&&c<='9')
	  x=x*10+c-'0';
	return x*f;
}
struct heap{
	priority_queue<int>q1,q2;int siz;
	IL void pre(){while(q2.size()&&q1.top()==q2.top()) q1.pop(),q2.pop();}
	IL void push(int x){q1.push(x),++siz;}
	IL void pop(int x){q2.push(x),--siz;}
	IL int top(){pre();return siz?q1.top():-inf;}
	IL int ask(){
		if(siz<2) return -inf;
		int x=top();pop(x);
		int y=top();push(x);
		return x+y;
	}
}q1[N],q2[N];
IL int max(int x,int y){return x>y?x:y;}
IL int min(int x,int y){return x<y?x:y;}
IL int chk(int x){return rs(fa[x])==x;}
IL int noroot(int x){return ls(fa[x])==x||rs(fa[x])==x;}
IL void pushup(int x){
	vsum[x]=vsum[ls(x)]+vsum[rs(x)]+val[x],
	mx[x]=max(mx[ls(x)],mx[rs(x)]),
	lv[x]=ls(x)?lv[ls(x)]:val[x];
	int Max=max(q1[x].top(),col[x]);
	lx[x]=max(lx[ls(x)],max(lx[rs(x)]+lv[rs(x)],Max)+val[x]+vsum[ls(x)]-lv[x]),
	rx[x]=max(rx[rs(x)],max(rx[ls(x)]+val[x],Max)+vsum[rs(x)]),
	mx[x]=max(mx[x],max(q1[x].ask(),q2[x].top())),
	mx[x]=max(mx[x],lx[rs(x)]+lv[rs(x)]+rx[ls(x)]+val[x]),
	mx[x]=max(mx[x],max(Max+rx[ls(x)]+val[x],Max+lx[rs(x)]+lv[rs(x)]));
	if(!col[x]) mx[x]=max(mx[x],q1[x].top());
}
IL void rotate(int x){
	int y=fa[x],z=fa[y],k=chk(x),w=ch[x][k^1];
	if(noroot(y)) ch[z][chk(y)]=x;
	if(w) fa[w]=y;
	fa[y]=x,fa[x]=z,ch[x][k^1]=y,ch[y][k]=w;
	pushup(y);
}
IL void splay(int x){
	while(noroot(x)){
		int y=fa[x];
		if(noroot(y))
		  rotate(chk(x)^chk(y)?x:y);
		rotate(x);
	}
	pushup(x);
}
IL void access(int x){
	for(int y=0;x;x=fa[y=x]){
		splay(x);
		if(rs(x)) q1[x].push(lx[rs(x)]+lv[rs(x)]),q2[x].push(mx[rs(x)]);
		if(rs(x)=y) q1[x].pop(lx[rs(x)]+lv[rs(x)]),q2[x].pop(mx[rs(x)]);
		pushup(x);
	}
}
IL void add(int x,int y,int z){e[++num]=(hh){y,fir[x],z},fir[x]=num;}
void dfs(int u,int f){
	for(int i=fir[u],v;v=e[i].to;i=e[i].nxt)
	  if(v^f){
	  	fa[v]=u,val[v]=e[i].w,dfs(v,u),
			q1[u].push(lx[v]+lv[v]),q2[u].push(mx[v]);
		}
	pushup(u);
}
int main()
{
	char op[10];int x,y,z;
	siz=n=in(),lx[0]=rx[0]=mx[0]=-inf;
	for(int i=1;i<n;++i)
	  x=in(),y=in(),z=in(),
	  add(x,y,z),add(y,x,z);
	dfs(1,0),ans=mx[1],m=in();
	while(m--){
		scanf("%s",op+1);
		if(op[1]=='C'){
			x=in(),access(x),splay(x);
			if(col[x]) col[x]=0,++siz;
			else col[x]=-inf,--siz;
			pushup(x),ans=mx[x];
		}
		else{
			if(siz==1) printf("0\n");
			else if(!siz) printf("They have disappeared.\n");
			else printf("%d\n",max(0,ans));
		}
	}
	return 0;
}
posted @ 2021-01-18 13:37  (o-ωq)).oO  阅读(72)  评论(0编辑  收藏  举报