洛谷:P3690 【模板】Link Cut Tree (动态树)
/*诸多细节,不注意就会调死去! 见注释。*/ #include<cstdio> #include<iostream> #include<algorithm> using namespace std; const int MAXN=300099; int n,m; int fa[MAXN],rev[MAXN],val[MAXN],xr[MAXN],Q[MAXN],ch[MAXN][2]; bool isroot(int x){ return ch[fa[x]][0]!=x && ch[fa[x]][1]!=x; } void Update(int x){ xr[x]=xr[ch[x][0]]^xr[ch[x][1]]^val[x]; } bool get(int x){ return ch[fa[x]][1]==x ;} void Down(int x){ if(rev[x]){ rev[ch[x][0]]^=1; rev[ch[x][1]]^=1; rev[x]^=1; swap(ch[x][0],ch[x][1]); } } void Rotate(int x) { int old=fa[x],oldf=fa[old],op=get(x); if(!isroot(old)) ch[oldf][ch[oldf][1]==old]=x; //这一条一定要放在改变父子关系之前!在纯Splay中是放在后面的,因为直接看oldf是否为0可知old是否为根。 ch[old][op]=ch[x][op^1]; fa[ch[x][op^1]]=old; //但这里使用isroot,改变之后就不能判断了! ch[x][op^1]=old; fa[old]=x; fa[x]=oldf; Update(old); Update(x); } void Splay(int x) { int tp=1; Q[1]=x; for(int i=x;!isroot(i);i=fa[i]) Q[++tp]=fa[i]; //对于LCT的判断是否是根节点,需要使用isroot,在纯Splay中使用的是fa,不要搞混! for(int i=tp;i;i--) Down(Q[i]); for(int FA; !isroot(x) ; Rotate(x)) { FA=fa[x]; if(!isroot(FA)) Rotate(get(x)==get(FA)?FA:x); } } void Access(int x){ int t=0; while(x){ Splay(x); ch[x][1]=t; Update(x); t=x; x=fa[x]; } } //记得Update void Makeroot(int x){ Access(x); Splay(x); rev[x]^=1;} void Link(int x,int y){ Makeroot(x); fa[x]=y; } void Cut(int x,int y){ Makeroot(x); Access(y); Splay(y); if(ch[y][0]==x) fa[x]=ch[y][0]=0;} int Find(int x){ Access(x); Splay(x); while(ch[x][0]) x=ch[x][0]; return x; } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%d",&val[i]) , xr[i]=val[i]; while(m--) { int x,y,op; scanf("%d%d%d",&op,&x,&y); if(op==0){ Makeroot(x); Access(y); Splay(y); printf("%d\n",xr[y]); } if(op==1){ if(Find(x)!=Find(y)) Link(x,y); } if(op==2){ Cut(x,y); } if(op==3){ Makeroot(x); val[x]=y; Update(x); } } return 0; }