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;
}