BZOJ4817: [Sdoi2017]樹點塗色【LCT+線段樹+LCA】

4817: [Sdoi2017]樹點塗色

我們發現1操作就是LCT的Access操作,對於每個1操作,在Access的同時構造Val數組,我們會發現當前實兒子所在的子樹Val++,Access後的實兒子Val–。所以可以用DFS序+線段樹進行維護。

2操作就是Val[x]+Val[y]-2*Val[fa]+1

3操作直接維護區間最大值就可以了。

#include<cmath>
#include<cstdio>
#include<algorithm>
using namespace std;
const int MAXN=100005;
int n,m,cnt,lg2,Dep[MAXN],Siz[MAXN],ID[MAXN],F[MAXN][20];
#include<cctype>
int read(){
	int ret=0;char ch=getchar();bool f=1;
	for(;!isdigit(ch);ch=getchar()) f^=!(ch^'-');
	for(; isdigit(ch);ch=getchar()) ret=ret*10+ch-48;
	return f?ret:-ret;
}
struct SGTree{
	int Tre[MAXN<<2],Add[MAXN<<2];
	void PushDown(int rt){
		if(!Add[rt]) return;
		Tre[rt<<1]+=Add[rt],Tre[rt<<1|1]+=Add[rt];
		Add[rt<<1]+=Add[rt];Add[rt<<1|1]+=Add[rt];
		Add[rt]=0;
	}
	void PushUp(int rt){Tre[rt]=max(Tre[rt<<1],Tre[rt<<1|1]);}
	void Insert(int rt,int L,int R,int l,int r,int p){
		if(l<=L&&R<=r){Tre[rt]+=p,Add[rt]+=p;return;}
		int mid=(R+L)>>1;PushDown(rt);
		if(l<=mid) Insert(rt<<1,L,mid,l,r,p);
		if(r>mid) Insert(rt<<1|1,mid+1,R,l,r,p);
		PushUp(rt);
	}
	int Ask(int rt,int L,int R,int l,int r){
		if(l<=L&&R<=r) return Tre[rt];
		int mid=(R+L)>>1,Ans=0;PushDown(rt);
		if(l<=mid) Ans=max(Ans,Ask(rt<<1,L,mid,l,r));
		if(r>mid) Ans=max(Ans,Ask(rt<<1|1,mid+1,R,l,r));
		return Ans;
	}
	int Query(int rt,int L,int R,int p){
		if(L==R) return Tre[rt];
		int mid=(L+R)>>1;PushDown(rt);
		if(p<=mid) return Query(rt<<1,L,mid,p);else return Query(rt<<1|1,mid+1,R,p);
	}
}SGT;
struct LCT{
	int Son[MAXN][2],Fa[MAXN];
	bool IsRoot(int x){return Son[Fa[x]][0]!=x&&Son[Fa[x]][1]!=x;}
	bool GetSon(int x){return Son[Fa[x]][1]==x;}
	void Rotate(int x){
		int L=GetSon(x),fa=Fa[x];
		if(!IsRoot(fa)) Son[Fa[fa]][GetSon(fa)]=x;
		Fa[Son[x][L^1]]=fa,Fa[x]=Fa[fa],Fa[fa]=x,Son[fa][L]=Son[x][L^1],Son[x][L^1]=fa;
	}
	void Splay(int x){for(;!IsRoot(x);Rotate(x)) if(!IsRoot(Fa[x])) Rotate((GetSon(Fa[x])^GetSon(x))?x:Fa[x]);}
	void Access(int x){
		for(int lst=0;x;lst=x,x=Fa[x]){
			Splay(x);
			if(Son[x][1]){
				int y=Son[x][1];
				while(Son[y][0]) y=Son[y][0];
				SGT.Insert(1,1,n,ID[y],ID[y]+Siz[y]-1,1);
			}
			Son[x][1]=lst;
			if(Son[x][1]){
				int y=Son[x][1];
				while(Son[y][0]) y=Son[y][0];
				SGT.Insert(1,1,n,ID[y],ID[y]+Siz[y]-1,-1);
			}
		}
	}
}T;
struct Edge{
	int tot,lnk[MAXN],son[MAXN<<1],nxt[MAXN<<1];
	void Add(int x,int y){son[++tot]=y;nxt[tot]=lnk[x];lnk[x]=tot;}
}E;
void DFS(int x,int fa){
	Dep[x]=Dep[fa]+1,ID[x]=++cnt,F[x][0]=fa,T.Fa[x]=fa;Siz[x]=1;
	for(int j=E.lnk[x];j;j=E.nxt[j]) if(E.son[j]!=fa) DFS(E.son[j],x),Siz[x]+=Siz[E.son[j]];
	SGT.Insert(1,1,n,ID[x],ID[x]+Siz[x]-1,1);
}
void INIT(){
	for(int j=1;(1<<j)<=n;j++)
	for(int i=1;i<=n;i++) F[i][j]=F[F[i][j-1]][j-1];
}
int LCA(int q,int p){
	if(Dep[p]<Dep[q]) swap(p,q);
	int Del=Dep[p]-Dep[q];
	for(int i=0;(1<<i)<=Del;i++) if((1<<i)&Del) p=F[p][i];
	if(p==q) return p;
	for(int i=lg2;i>=0;i--)
	if(F[p][i]^F[q][i]) p=F[p][i],q=F[q][i];
	return F[p][0];
}
int main(){
	#ifndef ONLINE_JUDGE
	freopen("4817.in","r",stdin);
	freopen("4817.out","w",stdout);
	#endif
	n=read(),m=read();lg2=log2(n);
	for(int i=1,x,y;i<n;i++) x=read(),y=read(),E.Add(x,y),E.Add(y,x);
	DFS(1,0);INIT();
	for(int i=1;i<=m;i++){
		int TYPE=read();
		if(TYPE==1){T.Access(read());}
		if(TYPE==2){
			int x=read(),y=read();
			int fa=LCA(x,y);
			printf("%d\n",SGT.Query(1,1,n,ID[x])+SGT.Query(1,1,n,ID[y])-SGT.Query(1,1,n,ID[fa])*2+1);
		}
		if(TYPE==3){int x=read();printf("%d\n",SGT.Ask(1,1,n,ID[x],ID[x]+Siz[x]-1));}
	}
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章