Link Cut Tree(无图慎入)

Posted idqi

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Link Cut Tree(无图慎入)相关的知识,希望对你有一定的参考价值。

类似树链剖分(其实直接记住就可以了),提前放代码

  1 #include<cstdio>
  2 #include<cstdlib>
  3 #include<iostream>
  4 #include<algorithm>
  5 #include<cstring>
  6 #include<climits>
  7 #include<cmath>
  8 #define N (int)(3e5+5)
  9 using namespace std;
 10 
 11 int n,m,st[N],z;
 12 struct tree 
 13 {
 14     int vi,si,son[2],rev,fa;
 15     #define vi(x) t[x].vi
 16     #define si(x) t[x].si
 17     #define fa(x) t[x].fa
 18     #define rev(x) t[x].rev
 19     #define son(x,y) t[x].son[y]
 20 } t[N];
 21 
 22 void pushup(int x) {si(x)=vi(x)^si(son(x,0))^si(son(x,1));}
 23 void pushr(int x) {swap(son(x,0),son(x,1));rev(x)^=1;}
 24 void pushdown(int x)
 25 {
 26     if(rev(x))
 27     {
 28         if(son(x,0)) pushr(son(x,0));
 29         if(son(x,1)) pushr(son(x,1));    
 30         rev(x)=0;
 31     }
 32 }
 33 
 34 int get(int x) {return son(fa(x),1)==x;}
 35 bool nroot(int x) {return son(fa(x),0)==x||son(fa(x),1)==x;}
 36 
 37 void rotate(int x)
 38 {
 39     int y=fa(x),z=fa(y),k=get(x);
 40     if(nroot(y)) son(z,get(y))=x;fa(x)=z;
 41     son(y,k)=son(x,k^1);if(son(y,k)) fa(son(y,k))=y;
 42     son(x,k^1)=y;fa(y)=x;pushup(y);pushup(x);
 43 }
 44 void Splay(int x)
 45 {
 46     int y=x;st[++(z=0)]=y;
 47     while(nroot(y)) st[++z]=y=fa(y);
 48     while(z) pushdown(st[z--]);
 49     while(nroot(x))
 50     {
 51         int y=fa(x),z=fa(y);
 52         if(nroot(y)) rotate(get(x)==get(y)?y:x);
 53         rotate(x);
 54     }
 55     pushup(x);
 56 }
 57 
 58 void access(int x)
 59 {
 60     for(int y=0;x;x=fa(y=x))
 61         Splay(x),son(x,1)=y,pushup(x);
 62 }
 63 void makeroot(int x)
 64 {
 65     access(x);Splay(x);
 66     pushr(x);pushup(x);    
 67 }
 68 void split(int x,int y) {makeroot(x);access(y);Splay(y);}
 69 int findroot(int x)
 70 {
 71     access(x);Splay(x);
 72     while(son(x,0)) pushdown(x),x=son(x,0);
 73     return x;
 74 }
 75 
 76 bool link(int x,int y)
 77 {
 78     makeroot(x);
 79     if(findroot(y)==x) return false;
 80     fa(x)=y;return true;
 81 }
 82 
 83 bool cut(int x,int y)
 84 {
 85     makeroot(x);
 86     if(findroot(y)!=x||fa(x)!=y||son(x,1)) return 1;
 87     fa(x)=son(y,0)=0;pushup(y);
 88 }
 89 
 90 int main()
 91 {
 92     scanf("%d%d",&n,&m);
 93     for(int i=1;i<=n;i++) scanf("%d",&vi(i));
 94     for(int i=1,type,x,y;i<=m;i++)
 95     {
 96         scanf("%d%d%d",&type,&x,&y);
 97         switch(type)
 98         {
 99             case 0:split(x,y);printf("%d
",si(y));break;
100             case 1:link(x,y);break;
101             case 2:cut(x,y);break;
102             case 3:Splay(x);vi(x)=y;    
103         }
104     }
105     return 0;
106 }

 

Link Cut Tree的一些注意:

  同一个Splay中没有相同深度点  

  Splay需要先放标记

  然后Splay的根的父亲不一定是0

  认父不认子,就是儿子父亲不变,但是父亲只记录一个儿子

 

核心操作:

  access 提取一个到根的路径

    考虑现在是一个由多个Splay组成的树(或者森林),首先肯定是将x转到根节点,然后直接换到这个Splay的整个父亲(就是Splay中深度最小的点的父亲),然后因为需要将整个Splay和父亲相连,为了维护性质,需要将它父亲的其他儿子断掉,直接Splay(父亲),然后将右边儿子改为这个Splay(注意这个是一个递推的过程)

  

  makeroot 将这个点变为整个树的根

    比较简单,主要首先就是开辟一条到根的路径,然后Splay,但是依旧不是深度最小的点,直接打入翻转标记即可

 

  然后。。。其他就通过这些直接推就可以了(其实就是比较懒

以上是关于Link Cut Tree(无图慎入)的主要内容,如果未能解决你的问题,请参考以下文章

P3690 模板Link Cut Tree (动态树)

题解 luogu P1501[国家集训队]Tree II(Link-Cut-Tree)

luogu3690 模板Link Cut Tree (动态树)

Link-Cut-Tree详解

AC日记——模板Link Cut Tree 洛谷 P3690

Link Cut Tree 总结