题解[P5649 Sone1]

题目链接
TopTree的板子怎么能用TopTree来写呢?
宣传一个并非 \(AAAT\) 的能保证时间复杂度的魔改 \(LCT\) 做法
更详细的介绍与时间复杂度分析:cnblog 洛谷blog
考虑用 \(splay\) 维护虚儿子,
但事实上如果单纯地让每个节点对应一个虚拟节点在对应的维护虚儿子的 \(splay\) 中,
\(AAAT\) 一样地写,并不能很好地保证单次 \(access\) 时间复杂度。
这主要是因为它删除节点时需将前驱(后继)找出来再删。
借鉴一下 \(Tarjan\)\(Top\) \(Tree\) 论文,不难发现另一种方法
就是把虚儿子 \(splay\) 中的真正代表原先 \(LCT\) 中信息的点只让它们在叶子结点上
然后用一些辅助节点串起来,构成一个类似 \(leafytree\) 的结构
若在删一个节点时,由于其没有左右儿子,直接连带他的父节点从整个 \(splay\) 中移除,
再将其原先父节点的父节点旋到根,更新一下即可。
同时若是换节点的信息,同样直接改然后旋到根更新信息,十分方便。
而这样是可以保证单次 \(access\) 是均摊时间为一个 \(log\) 的,具体证明参见上面的链接。
回到这题,由于题中标记众多,下面具体说明:

  1. 路径标记

由于路径修改并不会影响子树中其他路径的信息,所以需要在 \(pushup\) 时处理出
每个点在 \(LCT\)\(splay\) 中的子树的全部虚儿子信息,
这样才能在路径标记中快速得出每个点修改后的子树信息。

  1. 子树标记

子树标记处理方法并不能直接暴力地更改每个点的子树信息,
不然很容易应处理不当而出大问题。
为了避免与路径标记弄混,最好是将其拆成两个标记,
一个修改路劲,一个修改子树中除路径外的其他值。
在每个点被打上子树标记时同时将其虚儿子的 \(splay\) 打上标记。
在虚儿子的 \(splay\) 中被打上标记的叶子节点要将标记传出给 \(LCT\) 中的 \(splay\)
为了让标记不能一次连续传来传去,要给每个点对应的虚儿子的 \(splay\) 一个不动的根节点。

  1. 加与覆盖标记

无论是路径覆盖还是对子树中除路径外的信息覆盖时,会将加的标记抹去。
但覆盖完后出现的加的标记仍然生效。
于是要在打覆盖标记时要将加的标记清空,
\(pushdown\) 时先传覆盖的标记再传加的标记即可。
而至于路径标记与子树中除路径外的标记互不影响,顺序随意。

  1. 一个细节

在维护虚儿子的 \(splay\) 中,辅助节点众多,搞不准就会出现各种问题。
在标记下传时,尤其是覆盖标记,需看好能不能给这个节点一个最小或最大权值。

代码:

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
const int inf=0x7fffffff;
int n,m,x,y,opt,root;int v,ans;char ch;
int son[N][2],anc[N],sz[N][3],rt[N],rev[N];
int sum[N][3],w[N],add[N][2],cov[N][2],mn[N][3],mx[N][3];
void read(int &x){
	x=0;ch=getchar();
	while(ch<'0'||ch>'9')ch=getchar();
	while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
}
void write(int x){
	if(x>=10)write(x/10);
	putchar('0'+x%10);
}
void add_(int x,int v,bool b);
void cov_(int x,int v,bool b);
struct leafy_Splay{
	int son[N<<2][2],anc[N<<2],sz[N<<2],wsz[N<<2],tot;queue<int> q;
	int mn[N<<2],mx[N<<2],wmn[N<<2],wmx[N<<2],sum[N<<2],wsum[N<<2],add[N<<2],cov[N<<2];
	void init(int x){
		mx[x]=wmx[x]=-inf;
		mn[x]=wmn[x]=cov[x]=inf;
		son[x][0]=son[x][1]=anc[x]=sz[x]=wsz[x]=sum[x]=wsum[x]=add[x]=0;
	}
	void add_1(int x,int v){
		add[x]+=v;
		if(sz[x])sum[x]+=sz[x]*v,mn[x]+=v,mx[x]+=v;
		if(x<=n)wsum[x]+=wsz[x]*v,wmn[x]+=v,wmx[x]+=v,add_(x,v,1),add_(x,v,0);
	}
	void cov_1(int x,int v){
		cov[x]=v;add[x]=0;
		if(sz[x])sum[x]=sz[x]*v,mn[x]=mx[x]=v;
		if(x<=n)wsum[x]=wsz[x]*v,wmn[x]=wmx[x]=v,cov_(x,v,1),cov_(x,v,0);
	}
	void fix(int x){
		if(!x)return;
		sum[x]=sum[son[x][0]]+sum[son[x][1]]+wsum[x];
		sz[x]=sz[son[x][0]]+sz[son[x][1]]+wsz[x];
		mn[x]=min(min(mn[son[x][0]],mn[son[x][1]]),wmn[x]);
		mx[x]=max(max(mx[son[x][0]],mx[son[x][1]]),wmx[x]);
	}
	bool p(int x){return son[anc[x]][1]==x;}
	int newnode(){
		if(!q.empty()){
			int x=q.front();
			return q.pop(),x;
		}
		return init(++tot),tot;
	}
	void pushdown(int x){
		if(cov[x]!=inf){
			if(son[x][0])cov_1(son[x][0],cov[x]);
			if(son[x][1])cov_1(son[x][1],cov[x]);
			cov[x]=inf;
		}
		if(add[x]){
			if(son[x][0])add_1(son[x][0],add[x]);
			if(son[x][1])add_1(son[x][1],add[x]);
			add[x]=0;
		}
	}
	void pushall(int x){
		if(anc[x])pushall(anc[x]);
		pushdown(x);
	}
	void rotate(int x){
		int y=anc[x],xx=anc[y];
		bool b=p(x),bb=p(y);
		anc[x]=xx;
		if(xx)son[xx][bb]=x;
		son[y][b]=son[x][b^1];
		anc[son[x][b^1]]=y;
		son[x][b^1]=y;
		anc[y]=x;
		fix(y);
		fix(x);
		fix(xx);
	}
	void splay(int x,int y){
		pushall(x);
		for(int i=anc[x];i=anc[x],i!=y;rotate(x))if(anc[i]!=y){
			if(p(x)==p(i))rotate(i);
			else rotate(x);
		}
	}
	void ins(int x,int y,int sum_,int sz_,int mn_,int mx_){
		wsum[x]=sum_,wsz[x]=sz_,wmn[x]=mn_,wmx[x]=mx_;fix(x);
		int tmp=rt[y],f=0;pushdown(tmp);
		if(!son[rt[y]][0])return anc[son[rt[y]][0]=x]=rt[y],fix(rt[y]);
		while(1){
			if(!tmp){
				tmp=newnode();
				anc[son[anc[f]][p(f)]=tmp]=anc[f];
				son[tmp][x>f]=x;anc[x]=tmp;
				son[tmp][x<f]=f;anc[f]=tmp;
				fix(f);fix(tmp);fix(anc[tmp]);
				return splay(tmp,rt[y]);
			}
			pushdown(tmp);
			f=tmp;tmp=son[tmp][x>tmp];
		}
	}
	void clear(int x){init(x);if(x>2*n)q.push(x);}
	void del(int x,int y){
		if(anc[x]==rt[y])return son[rt[y]][0]=0,fix(rt[y]),clear(x);
		int yy=anc[x],xx=anc[yy];bool b=p(x),bb=p(yy);
		if(xx==rt[y]){
			anc[son[rt[y]][0]=son[yy][b^1]]=rt[y];
			clear(x),clear(yy),fix(rt[y]);
			return;
		}
		anc[son[xx][bb]=son[yy][b^1]]=xx;
		clear(x);clear(yy);fix(xx);splay(xx,rt[y]);fix(rt[y]);
	}
	void display(int x,int xx,int sum_,int sz_,int mn_,int mx_,int y){
		wsum[xx]=sum_,wsz[xx]=sz_,wmn[xx]=mn_,wmx[xx]=mx_;fix(xx);
		int yy=anc[x];
		anc[son[yy][p(x)]=xx]=yy;
		clear(x);fix(yy);if(yy!=rt[y])splay(yy,rt[y]);fix(rt[y]);
	}
}S;
void update(int x){
	sz[x][2]=sz[x][0]+sz[x][1];
	sum[x][2]=sum[x][0]+sum[x][1];
	mn[x][2]=min(mn[x][0],mn[x][1]);
	mx[x][2]=max(mx[x][0],mx[x][1]);
}
void rev_(int x){rev[x]^=1;son[x][0]^=son[x][1]^=son[x][0]^=son[x][1];}
void add_(int x,int v,bool b){
	add[x][b]+=v;
	if(sz[x][b])sum[x][b]+=sz[x][b]*v,mn[x][b]+=v,mx[x][b]+=v;
	if(b)S.add_1(rt[x],v);
	else w[x]+=v;
	update(x);
}
void cov_(int x,int v,bool b){
	cov[x][b]=v;add[x][b]=0;
	if(sz[x][b])sum[x][b]=sz[x][b]*v,mn[x][b]=mx[x][b]=v;
	if(b)S.cov_1(rt[x],v);
	else w[x]=v;
	update(x);
}
bool p(int x){return son[anc[x]][1]==x;}
bool isroot(int x){return son[anc[x]][0]!=x&&son[anc[x]][1]!=x;}
void S_display(int x,int xx,int y){
	S.display(x,xx,sum[xx][2],sz[xx][2],mn[xx][2],mx[xx][2],y);
}
void S_ins(int x,int y){
	S.ins(x,y,sum[x][2],sz[x][2],mn[x][2],mx[x][2]);
}
void fix(int x){
	if(!x)return;
	
	sz[x][0]=sz[son[x][0]][0]+sz[son[x][1]][0]+1;
	sz[x][1]=sz[son[x][0]][1]+sz[son[x][1]][1]+S.sz[rt[x]];
	
	sum[x][0]=sum[son[x][0]][0]+sum[son[x][1]][0]+w[x];
	sum[x][1]=sum[son[x][0]][1]+sum[son[x][1]][1]+S.sum[rt[x]];
	
	mn[x][0]=min(min(mn[son[x][0]][0],mn[son[x][1]][0]),w[x]);
	mn[x][1]=min(min(mn[son[x][0]][1],mn[son[x][1]][1]),S.mn[rt[x]]);
	
	mx[x][0]=max(max(mx[son[x][0]][0],mx[son[x][1]][0]),w[x]);
	mx[x][1]=max(max(mx[son[x][0]][1],mx[son[x][1]][1]),S.mx[rt[x]]);
	
	update(x);
}
void pushdown(int x){
	if(rev[x]){
		if(son[x][0])rev_(son[x][0]);
		if(son[x][1])rev_(son[x][1]);
		rev[x]=0;
	}
	if(cov[x][0]!=inf){
		if(son[x][0])cov_(son[x][0],cov[x][0],0);
		if(son[x][1])cov_(son[x][1],cov[x][0],0);
		cov[x][0]=inf;
	}
	if(add[x][0]){
		if(son[x][0])add_(son[x][0],add[x][0],0);
		if(son[x][1])add_(son[x][1],add[x][0],0);
		add[x][0]=0;
	}
	if(cov[x][1]!=inf){
		if(son[x][0])cov_(son[x][0],cov[x][1],1);
		if(son[x][1])cov_(son[x][1],cov[x][1],1);
		cov[x][1]=inf;
	}
	if(add[x][1]){
		if(son[x][0])add_(son[x][0],add[x][1],1);
		if(son[x][1])add_(son[x][1],add[x][1],1);
		add[x][1]=0;
	}
}
void pushall(int x){
	if(!isroot(x))pushall(anc[x]);
	pushdown(x);
}
void pushall_(int x){
	if(!isroot(x))pushall_(anc[x]);
	else if(anc[x]){
		pushall_(anc[x]);
		S.pushall(x);
	}
	pushdown(x);
}
void rotate(int x){
	int y=anc[x],xx=anc[y];
	bool b=p(x),bb=p(y);
	anc[x]=xx;
	if(!isroot(y))son[xx][bb]=x;
	son[y][b]=son[x][b^1];
	anc[son[x][b^1]]=y;
	son[x][b^1]=y;
	anc[y]=x;
	fix(y);
	fix(x);
	fix(xx);
}
int findrt(int x){
	if(isroot(x))return x;
	return findrt(anc[x]);
}
void splay(int x){
	pushall(x);
	int y=findrt(x);
	if(anc[y]&&x!=y)S.display(y,x,sum[y][2],sz[y][2],mn[y][2],mx[y][2],anc[y]);
	for(int i=anc[x];i=anc[x],!isroot(x);rotate(x))if(!isroot(i)){
		if(p(i)==p(x))rotate(i);
		else rotate(x);
	}
}
int access(int x){
	int y=0;
	pushall_(x);
	for(;x;y=x,x=anc[x]){
		splay(x);
		if(y&&son[x][1])S_display(y,son[x][1],x);
		else if(!y&&son[x][1])S_ins(son[x][1],x);
		else if(y&&!son[x][1])S.del(y,x);
		son[x][1]=y;fix(x);
	}
	return y;
}
void makeroot(int x){
	access(x);
	splay(x);
	rev_(x);
}
void split(int x,int y){
	makeroot(x);
	access(y);
	splay(y);
}
void link(int x,int y){
	split(x,y);
	anc[x]=y;
	S_ins(x,y);
	fix(y);
}
void subtree_add(int x,int v){
	split(root,x);
	w[x]+=v;
	S.add_1(rt[x],v);
	fix(x);
}
void subtree_cov(int x,int v){
	split(root,x);
	w[x]=v;
	S.cov_1(rt[x],v);
	fix(x);
}
int pre(int x){
	pushdown(x=son[x][0]);
	while(son[x][1])pushdown(x=son[x][1]);
	return splay(x),x;
}
int lca(int x,int y){
	makeroot(root);
	access(x);
	return access(y);
}
void cut(int x,int y){
	split(x,y);
	anc[x]=son[y][0]=0;
	fix(y);
}
void move(int x,int xx){
	if(lca(x,xx)==x)return;
	split(root,x);
	int y=pre(x);
	cut(x,y);link(x,xx);
}
int a[15]={4,0,2,9,10,3,1,6,7,11,5,8};
int xx[N],yy[N];
main(){
//	freopen("2.in","r",stdin);freopen("zt.txt","w",stdout);
	read(n);read(m);S.tot=n<<1;
	mn[0][0]=mn[0][1]=mn[0][2]=S.mn[0]=S.wmn[0]=inf;
	mx[0][0]=mx[0][1]=mx[0][2]=S.mx[0]=S.wmx[0]=-inf;
	for(int i=1;i<n;i++)read(xx[i]),read(yy[i]);
	for(int i=1;i<=n;i++){
		read(w[i]);
		fix(i);
		S.init(rt[i]=i+n);
		cov[i][0]=cov[i][1]=inf;
	}
	for(int i=1;i<n;i++)link(xx[i],yy[i]);
	read(root);
	while(m--){
		read(opt);read(x);opt=a[opt];
		if(opt==0)root=x;
		if(opt==1)read(y),read(v),split(x,y),add_(y,v,0);
		if(opt==2)read(y),read(v),split(x,y),cov_(y,v,0);
		if(opt==3)read(v),subtree_add(x,v);
		if(opt==4)read(v),subtree_cov(x,v);
		if(opt==5)read(y),split(x,y),write(sum[y][0]);
		if(opt==6)read(y),split(x,y),write(mn[y][0]);
		if(opt==7)read(y),split(x,y),write(mx[y][0]);
		if(opt==8)split(root,x),ans=S.sum[rt[x]]+w[x],write(ans);
		if(opt==9)split(root,x),ans=min(S.mn[rt[x]],w[x]),write(ans);
		if(opt==10)split(root,x),ans=max(S.mx[rt[x]],w[x]),write(ans);
		if(opt==11)read(y),move(x,y);
		if(opt>=5&&opt<=10)putchar('\n');
	}
}
posted @ 2021-07-13 15:03  Y_B_X  阅读(42)  评论(0编辑  收藏  举报