1. 程式人生 > >Link Cut Tree(無圖慎入)

Link Cut Tree(無圖慎入)

clas 提取 rotate true urn find ring namespace !=

類似樹鏈剖分(其實直接記住就可以了),提前放代碼

  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\n",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(無圖慎入)