LCT摘要

介紹、用途

LCT是樹鏈剖分中的一種,又叫實鏈剖分、動態樹,經常使用於維護動態的樹、森林。php

維護方式

LCT並不直接維護原樹,而是用一堆splay做爲輔助樹來維護。原樹中的一條實鏈上的點在一棵splay中,虛邊體現爲輔助上的鏈接兩棵splay的虛邊,只認爸爸不認兒子。c++

變量介紹

 1 int n,m;  2 struct Node {  3     int fa,son[2];                                                                                            //爸爸、兒子(0左1右)
 4     int val,all;                                                                                            //該點權值、子樹異或和
 5     char ifz;                                                                                                //是否翻轉(0否1是)
 6     void res() {                                                                                            //重置(然並卵)
 7         fa=son[0]=son[1]=val=0;  8  }  9 } tree[maxn]; 10 int pre[maxn],inp;                                                                                            //翻轉序列(splay用)
var

各類操做

判斷一個點是哪一個兒子

很少說了git

1 char which(int x) { 2     return x==tree[tree[x].fa].son[1]; 3 }
which

判斷一個點是否是該splay的根

也很少說了ide

1 char isroot(int x) { 2     return x!=tree[tree[x].fa].son[which(x)]; 3 }
isroot

splay的操做

 1 void rotate(int x) {  2     int f=tree[x].fa,ff=tree[f].fa,c=which(x);  3     if(!isroot(f)) tree[ff].son[which(f)]=x;                                                                //若它爸是根就不要搞它爺了
 4     tree[x].fa=ff;  5     tree[f].son[c]=tree[x].son[c^1];  6     tree[tree[f].son[c]].fa=f;  7     tree[x].son[c^1]=f;  8     tree[f].fa=x;  9  update(f); 10  update(x); 11 } 12 void splay(int x) { 13     int f; 14     pre[inp=1]=x; 15     for(f=x; !isroot(f); f=tree[f].fa) pre[++inp]=tree[f].fa;                                                //挖出它到根的點
16     fdi(i,inp,1,1) pushdown(pre[i]);                                                                        //所有pushdown
17     for(; !isroot(x); rotate(x))if(!isroot(tree[x].fa))rotate((which(tree[x].fa)^which(x))?x:tree[x].fa);    //無需pushdown
18 }
splay

打通這個點到原樹的根爲實鏈

這個是重點!!!是LCT的核心!!!ui

首先,先將該節點splay到根,並將其爸爸splay到根。因而咱們知道,它爸爸的右兒子深度大於它爸爸,是須要砍成虛邊的點,而它的深度也大於它爸爸,因此直接將它爸爸的右兒子變成它。重複上述操做,直到它無爸爸。spa

1 void access(int x) { 2     for(int pr=0; x; pr=x,x=tree[x].fa)splay(x),tree[x].son[1]=pr,update(x); 3 }
access

將這個點變成原樹的根

先打通這個點到根,並將它splay到根。而後咱們能夠發現,不在這棵splay上的點不受影響,而這棵splay上的點深淺顛倒,對應到splay上就是區間翻轉。因此給它打上一個翻轉標記。3d

1 void makeroot(int x) { 2  access(x); 3  splay(x); 4     tree[x].ifz^=1;                                                                                            //打翻轉標記
5 }
makeroot

查找這個點所在原樹的根

先打通它到根並splay,而後找到它所在splay的最左邊的點(即一直往左兒子找)。code

1 int find(int x) { 2     for(access(x),splay(x); tree[x].son[0]; x=tree[x].son[0]); 3     return x; 4 }
find

鏈接個點並鏈接兩棵樹

將一個點變成根,並令這個點爸爸爲另外一個點。注意先判斷這兩個點在不在一棵樹內,在就不用連了。blog

1 void link(int x,int y) { 2  makeroot(x); 3     tree[x].fa=y; 4 }
link

切斷兩點之間的邊

先判斷在不在一棵樹內,不在就不切。而後將一個點變成根,另外一個點打通到根並splay到根。易發現若這兩個點間有邊則這棵splay中只有它們倆。判斷一下便可。get

1 void cut(int x,int y) { 2  makeroot(x); 3  access(y); 4  splay(y); 5     if(tree[y].son[0]==x&&!tree[y].son[1]&&!tree[x].son[0]&&!tree[x].son[1])tree[y].son[0]=tree[x].fa=0; 6 }
cut

改變一個點的值

將這個點變成根,並將其splay,再改變權值便可。

1 void change(int x,int y) { 2  makeroot(x); 3  splay(x); 4     tree[x].val=y; 5  update(x); 6 }
change

查詢x到y的異或和

將x變成根,打通y並splay,直接查詢便可。

1 int query(int x,int y) { 2  makeroot(x); 3  access(y); 4  splay(y); 5     return tree[y].all; 6 }
query

時空複雜度

時間複雜度

splay:均攤O(logn)的不用說了吧

access:因爲每次access最多有logn條實邊變成虛邊,splay複雜度也僅爲均攤O(logn),所以時間複雜度均攤O(logn)

makeroot:makeroot的開銷主要爲access,所以也爲均攤O(logn)

其餘:基於以上三種操做,所以都爲均攤O(logn)

只是常數無比巨大!!!
只是常數無比巨大!!!
只是常數無比巨大!!!

空間複雜度

顯然是O(n)的

題目

洛谷P3690 【模板】Link Cut Tree (動態樹)

 1 #include<bits/stdc++.h>
 2 using namespace std;  3 #define ImaxnF 0x7fffffff
 4 #define ME 0x7f
 5 #define FO(s) freopen(s".in","r",stdin);freopen(s".out","w",stdout)
 6 #define fui(i,a,b,c) for(int i=(a);i<=(b);i+=(c))
 7 #define fdi(i,a,b,c) for(int i=(a);i>=(b);i-=(c))
 8 #define fel(i,a) for(register int i=h[a];i;i=ne[i])
 9 #define ll long long
10 #define MEM(a,b) memset(a,b,sizeof(a))
11 #define maxn (300000+10)
12 int n,m; 13 struct Node{ 14     int fa,son[2]; 15     int val,all;//,siz;
16     char ifz; 17     void res(){fa=son[0]=son[1]=val=/*siz=*/0;} 18 }tree[maxn]; 19 int pre[maxn],inp; 20 template<class T>
21 inline T read(T &n){ 22     n=0;int t=1;char ch; 23     for(ch=getchar();!isdigit(ch)&&ch!='-';ch=getchar());(ch=='-')?t=-1:n=ch-'0'; 24     for(ch=getchar();isdigit(ch);ch=getchar()) n=n*10+ch-'0'; 25     return (n*=t); 26 } 27 template<class T>
28 T write(T n){ 29     if(n<0) putchar('-'),n=-n; 30     if(n>=10) write(n/10);putchar(n%10+'0'); 31 } 32 template<class T>
33 T writeln(T n){ 34     write(n);putchar('\n'); 35 } 36 char which(int x){return x==tree[tree[x].fa].son[1];} 37 char isroot(int x){return x!=tree[tree[x].fa].son[which(x)];} 38 void update(int x){tree[x].all=tree[tree[x].son[0]].all^tree[tree[x].son[1]].all^tree[x].val;} 39 void pushdown(int x){ 40     if(tree[x].ifz){ 41         tree[x].ifz=0,swap(tree[x].son[0],tree[x].son[1]); 42         tree[tree[x].son[0]].ifz^=1,tree[tree[x].son[1]].ifz^=1; 43  } 44 }void rotate(int x){ 45     int f=tree[x].fa,ff=tree[f].fa,c=which(x);if(!isroot(f)) tree[ff].son[which(f)]=x; 46     tree[x].fa=ff;tree[f].son[c]=tree[x].son[c^1];tree[tree[f].son[c]].fa=f; 47     tree[x].son[c^1]=f;tree[f].fa=x;update(f);update(x); 48 }void splay(int x){ 49     int f;pre[inp=1]=x;for(f=x;!isroot(f);f=tree[f].fa) pre[++inp]=tree[f].fa;fdi(i,inp,1,1) pushdown(pre[i]); 50     for(;!isroot(x);rotate(x))if(!isroot(tree[x].fa))rotate((which(tree[x].fa)^which(x))?x:tree[x].fa);//update(x);
51 }void access(int x){for(int pr=0;x;pr=x,x=tree[x].fa)splay(x),tree[x].son[1]=pr,update(x);} 52 void makeroot(int x){access(x);splay(x);tree[x].ifz^=1;} 53 int find(int x){for(access(x),splay(x);tree[x].son[0];x=tree[x].son[0]);return x;} 54 void cut(int x,int y){makeroot(x);access(y);splay(y);if(tree[y].son[0]==x&&!tree[y].son[1]&&!tree[x].son[0]&&!tree[x].son[1]/*tree[y].siz==2*/)tree[y].son[0]=tree[x].fa=0;} 55 void link(int x,int y){makeroot(x);tree[x].fa=y;} 56 void change(int x,int y){makeroot(x);splay(x);tree[x].val=y;update(x);} 57 int query(int x,int y){makeroot(x);access(y);splay(y);return tree[y].all;} 58 int main(){ 59  read(n);read(m); 60     fui(i,1,n,1) tree[i].val=read(tree[i].all); 61     fui(i,1,m,1){ 62         int opt,x,y; 63  read(opt);read(x);read(y); 64         switch(opt){ 65             case 0:writeln(query(x,y));break; 66             case 1:if(find(x)!=find(y)) link(x,y);break; 67             case 2:if(find(x)==find(y)) cut(x,y);break; 68             case 3:change(x,y); 69  } 70  } 71     return 0; 72 }
AC代碼

BZOJ2049 [Sdoi2008]Cave 洞穴勘測

 1 #include<bits/stdc++.h>
 2 using namespace std;  3 #define ImaxnF 0x7fffffff
 4 #define ME 0x7f
 5 #define FO(s) freopen(s".in","r",stdin);freopen(s".out","w",stdout)
 6 #define fui(i,a,b,c) for(int i=(a);i<=(b);i+=(c))
 7 #define fdi(i,a,b,c) for(int i=(a);i>=(b);i-=(c))
 8 #define fel(i,a) for(register int i=h[a];i;i=ne[i])
 9 #define ll long long
10 #define MEM(a,b) memset(a,b,sizeof(a))
11 #define maxn (10000+10)
12 int n,m; 13 struct Node{ 14     int fa,son[2]; 15     char ifz; 16 }tree[maxn]; 17 int pre[maxn],inp; 18 template<class T>
19 inline T read(T &n){ 20     n=0;int t=1;double x=10;char ch; 21     for(ch=getchar();!isdigit(ch)&&ch!='-';ch=getchar());(ch=='-')?t=-1:n=ch-'0'; 22     for(ch=getchar();isdigit(ch);ch=getchar()) n=n*10+ch-'0'; 23     if(ch=='.') for(ch=getchar();isdigit(ch);ch=getchar()) n+=(ch-'0')/x,x*=10; 24     return (n*=t); 25 } 26 char which(int x){return x==tree[tree[x].fa].son[1];} 27 char isroot(int x){return x!=tree[tree[x].fa].son[which(x)];} 28 void pushdown(int x){ 29     if(tree[x].ifz){ 30         tree[x].ifz=0,swap(tree[x].son[0],tree[x].son[1]); 31         tree[tree[x].son[0]].ifz^=1,tree[tree[x].son[1]].ifz^=1; 32  } 33 } 34 void rotate(int x){ 35     int f=tree[x].fa,ff=tree[f].fa,c=which(x);if(!isroot(f)) tree[ff].son[which(f)]=x; 36     tree[x].fa=ff;tree[f].son[c]=tree[x].son[c^1];tree[tree[f].son[c]].fa=f; 37     tree[x].son[c^1]=f;tree[f].fa=x; 38 } 39 void splay(int x){ 40     int f;pre[inp=1]=x;for(f=x;!isroot(f);f=tree[f].fa) pre[++inp]=tree[f].fa;fdi(i,inp,1,1) pushdown(pre[i]); 41     for(;!isroot(x);rotate(x))if(!isroot(tree[x].fa))rotate((which(tree[x].fa)^which(x))?x:tree[x].fa); 42 } 43 void access(int x){for(int pr=0;x;pr=x,x=tree[x].fa)splay(x),tree[x].son[1]=pr;} 44 void makeroot(int x){access(x);splay(x);tree[x].ifz^=1;} 45 int find(int x){for(access(x),splay(x);tree[x].son[0];x=tree[x].son[0]);return x;} 46 void cut(int x,int y){makeroot(x);access(y);splay(y);if(tree[y].son[0]==x&&!tree[y].son[1]&&!tree[x].son[0]&&!tree[x].son[1])tree[y].son[0]=tree[x].fa=0;} 47 void link(int x,int y){makeroot(x);tree[x].fa=y;} 48 int main(){ 49  read(n);read(m); 50     fui(i,1,m,1){ 51         int x,y;char opt; 52         for(opt=getchar();opt!='Q'&&opt!='C'&&opt!='D';opt=getchar());read(x);read(y); 53         switch(opt){ 54             case 'Q':puts((find(x)==find(y))?"Yes":"No");break; 55             case 'C':if(find(x)!=find(y)) link(x,y);break; 56             case 'D':cut(x,y);break; 57  } 58  } 59     return 0; 60 }
AC代碼
相關文章
相關標籤/搜索