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(无图慎入)的主要内容,如果未能解决你的问题,请参考以下文章
题解 luogu P1501[国家集训队]Tree II(Link-Cut-Tree)
luogu3690 模板Link Cut Tree (动态树)