[Data]Link cut tree

Link Cut Tree

其实本人觉得LCT对于已经学过树剖与Splay的大佬是很容易理解接受的;

LCT是有树链与Splay结合而成的动态树;什么是动态树呢,就是维护森林的联通性的总称;

先介绍一些概念:

1.prefered child:最后被它的点在x的儿子p节点的子树中,那么p为x的偏爱子节点(相当于树剖中的重儿子)

2.prefered edge:父节点与它的偏爱子节点的边(相当于树剖中的重边)

3.prefered path:由偏爱边连接而成的路径为偏爱路径(相当于树剖中的重链)

我们学LCT时可以发现,每个点只在一条prefered path上,那么这样的话所有的prefered path就可以表示整棵树了,我们可以在每条prefered path 上建一棵splay,关键字为深度

也就是在每棵Splay中,左节点的深度都比当前节点小,右节点的深度都比当前节点深度大;这样,每棵spaly我们把它称作Auxiliary tree(辅助树),每棵辅助树的根节点的父亲

保存与上一棵辅助树的哪个点相连;整棵Splay在原树上相当于一条链(中序遍历);

 原树中的深度是递增的,辅助树中的左右子树是以深度为权值的!

易混点:

   原树的根节点!=辅助树中的根节点

   原树的左右儿子不等于辅助树的左右儿子

现在来说下一些基本操作

   1.access(x) 访问x节点:切断x与其原先Prefered child 的联系,由于prefered path与prefered child的定义,我们访问一个节点,那么这个点到根节点的所有边都是prefered edge;由于每个点只能有一个prefered child;所以我们需把节点与它原来的prefered child断开,连接这条新的prefered path;先把x splay到根节点,然后更新它的右子节点,直到x的fa 为空;

   2.make root(x) access(x)后,splay到根,然后由于权值是深度,所以为了维护左子树权值小于右子树性质,我们还需区间翻转一下;

   3.link(x,y) 连边,只需makeroot(x),然后把x的父亲指向y即可;

   4.cut(x,y) 删边,先makeroot(x),然后access(y),此时x与y已在同一棵splay中,然后再splay(y),那么x就在y的左儿子中;

最后放下代码:(luogu 3690)

  1 #include<cstdio>
  2 #include<cmath>
  3 #include<algorithm>
  4 #define maxn 300233
  5 using namespace std;
  6 int stack[maxn];
  7 struct hh{
  8     int c[2],fa,val,sum;
  9     bool rev;
 10 }tree[maxn];
 11 int read(){
 12     int s=0;
 13     char c=getchar();
 14     while(c<48||c>57) c=getchar();
 15     while(c>=48&&c<=57){
 16     s=s*10+c-48;c=getchar();}
 17     return s;
 18 }
 19 
 20 inline void update(int x){
 21     tree[x].sum=tree[tree[x].c[0]].sum^tree[x].val
 22     ^tree[tree[x].c[1]].sum;
 23 }
 24 inline void pushdown(int x){
 25     if(!tree[x].rev) return;
 26     int l=tree[x].c[0],r=tree[x].c[1];
 27     if(l) tree[l].rev^=1;
 28     if(r) tree[r].rev^=1;
 29     swap(tree[x].c[0],tree[x].c[1]);
 30     tree[x].rev^=1;
 31 }
 32 bool isroot(int x){
 33     return tree[tree[x].fa].c[0]!=x&&tree[tree[x].fa].c[1]!=x;
 34 }
 35 bool get(int x) {
 36 return x==tree[tree[x].fa].c[1];}
 37 void rotate(int x){
 38     int f=tree[x].fa,ff=tree[tree[x].fa].fa,opt=get(x);
 39     tree[f].c[opt]=tree[x].c[opt^1];
 40     tree[tree[x].c[opt^1]].fa=f; 
 41     if(!isroot(f)) tree[ff].c[get(f)]=x;
 42     tree[x].fa=ff;tree[f].fa=x;
 43     tree[x].c[opt^1]=f;
 44     update(f);update(x);
 45 }
 46 void splay(int x){
 47     //pushdown(x);
 48     int top=0,tmp=x;stack[++top]=x;
 49     while(!isroot(tmp))stack[++top]=tree[tmp].fa,tmp=tree[tmp].fa;
 50     while(top)pushdown(stack[top]),top--;
 51     while(!isroot(x)){
 52     //    if(!isroot(tree[x].fa)) rotate(get(tree[x].fa)==get(x)?tree[x].fa:x);
 53     //    x=tree[x].fa;
 54         rotate(x); 
 55     }
 56 } 
 57 void access(int x){
 58     int son=0;
 59     while(x){
 60         splay(x);tree[x].c[1]=son;
 61         update(x);son=x;x=tree[x].fa;
 62     }
 63 }
 64 void makeroot(int x){
 65     access(x);splay(x);tree[x].rev^=1;
 66 }
 67 void link(int x,int y){
 68     makeroot(x);tree[x].fa=y;
 69     splay(x);
 70 }
 71 void cut(int x,int y){
 72     makeroot(x);access(y);
 73     splay(y);tree[y].c[0]=tree[x].fa=0;
 74 }
 75 int query(int x,int y){
 76     makeroot(x);access(y);splay(y);
 77     return tree[y].sum;
 78 }
 79 int getfa(int x){
 80     access(x);splay(x);
 81     while(tree[x].c[0]){
 82         pushdown(x);x=tree[x].c[0];
 83         splay(x);
 84     } 
 85     return x;
 86 }
 87 void change(int x,int y){
 88     makeroot(x);
 89     tree[x].val=y;
 90     update(x);
 91 }
 92 int main(){
 93     int n,m,i,x,y,opt;
 94     n=read();m=read();
 95     for(i=1;i<=n;i++){
 96         tree[i].val=read();
 97         tree[i].sum=tree[i].val;
 98     }
 99     while(m--){
100         opt=read();x=read();y=read();
101         if(opt==0) printf("%d\n",query(x,y));
102         else if(opt==1) {if(getfa(x)!=getfa(y))link(x,y);}
103         else if(opt==2) {if(getfa(x)==getfa(y)) cut(x,y);}
104         else change(x,y);}
105 }
View Code

 

posted @ 2018-01-01 14:11  Konnyaku  阅读(190)  评论(0)    收藏  举报