LCT 动态树 模板

洛谷: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;
}
posted @ 2017-12-14 21:35  D_O_Time  阅读(445)  评论(0编辑  收藏  举报