1. 程式人生 > >Luogu P4299 首都 LCT

Luogu P4299 首都 LCT

既然是中文題目,這裡便不給題意。

分析:

  這個題的做法據說是啟發式合併?

  但是我不會啊……

  進入正題,LCT是怎樣做掉這道題的。記得在前面的一篇《大融合》的題解中,介紹過LCT維護子樹資訊的做法。

  一句話概括就是要維護虛子樹和實子樹的size,適時修改,保持其正確性。

  這道題關鍵並不在這,但我們必須要維護這樣一個資訊才可以做。

  很簡單很直觀的一個想法,因為我們每次合併兩棵樹時,新的重心必然出現在原來兩個重心的路徑上。

  這是為什麼?我們假設如果不在這條路徑上,而是其中一棵樹的其他子樹的某一點,那麼我們發現這一點比起之前,size較大的一棵子樹上又綴了一棵樹(以這個點為根),所以一定不優。

  於是我們就合併樹後把兩棵原樹的重心打通,(放到一個splay裡),這時候尺寸就派上用場了,我們就在這個splay裡查詢,因為重心反正肯定存在於這個splay中了,那麼我們就維護一個左尺寸,一個右尺寸。左邊大了我們就讓重心往左移動,右邊大了就往右移動,直到兩邊的尺寸都小於等於總尺寸的一半,就好啦!(別忘了多個重心時的編號最小化)

程式碼:

 1 #include<bits/stdc++.h>
 2 #define lc(x) t[x][0]
 3 #define rc(x) t[x][1]
 4 using namespace std;
 5 const int N=100005
; 6 const int inf=0x3f3f3f3f; 7 struct LCT{ 8 int t[N][2],s[N],rev[N],fa[N],sx[N],sz[N],tp; 9 void pushup(int x){ 10 sz[x]=sz[lc(x)]+sz[rc(x)]+sx[x]+1; 11 } bool pdrt(int x){ 12 return rc(fa[x])!=x&&lc(fa[x])!=x; 13 } void revers(int x){ 14 rev[x]^=1
;swap(lc(x),rc(x)); 15 } void pushdown(int x){ 16 if(rev[x]){ rev[x]=0; 17 if(lc(x)) revers(lc(x)); 18 if(rc(x)) revers(rc(x)); 19 } return ; 20 } void rotate(int x){ 21 int y=fa[x];int z=fa[y]; 22 int dy=(rc(y)==x),dz=(rc(z)==y); 23 if(!pdrt(y)) t[z][dz]=x; 24 t[y][dy]=t[x][dy^1];fa[t[y][dy]]=y; 25 t[x][dy^1]=y;fa[y]=x;fa[x]=z; 26 pushup(y);return ; 27 } void splay(int x){ 28 s[++tp]=x; 29 for(int i=x;!pdrt(i);i=fa[i]) 30 s[++tp]=fa[i]; 31 while(tp) pushdown(s[tp--]); 32 while(!pdrt(x)){ 33 int y=fa[x];int z=fa[y]; 34 if(!pdrt(y)) 35 if(rc(y)==x^rc(z)==y) rotate(x); 36 else rotate(y);rotate(x); 37 } pushup(x);return ; 38 } void access(int x){ 39 for(int i=0;x;x=fa[i=x]) 40 splay(x),sx[x]+=sz[rc(x)], 41 sx[x]-=sz[rc(x)=i],pushup(x); 42 } void mkrt(int x){ 43 access(x);splay(x);revers(x); 44 } void split(int x,int y){ 45 mkrt(x);access(y);splay(y); 46 } void link(int x,int y){ 47 split(x,y);sx[fa[x]=y]+=sz[x]; 48 pushup(y); 49 } int update(int x){ 50 int l,r,o=sz[x]&1,sm=sz[x]>>1, 51 ls=0,rs=0,np=inf,nl,nr; 52 while(x){ 53 pushdown(x); 54 nl=sz[l=lc(x)]+ls;nr=sz[r=rc(x)]+rs; 55 if(nl<=sm&&nr<=sm){ 56 if(o){np=x;break;} 57 else if(np>x) np=x; 58 } if(nl<nr) ls+=sz[l]+sx[x]+1,x=r; 59 else rs+=sz[r]+sx[x]+1,x=l; 60 } splay(np);return np; 61 } 62 }t;int n,m,fa[N]; 63 int get(int x){ 64 return fa[x]==x?x:fa[x]=get(fa[x]); 65 } int main(){ 66 char c[5];int rox=0;//尤為重要,必須賦0; 67 scanf("%d%d",&n,&m); 68 for(int i=1;i<=n;i++) 69 t.sz[i]=1,fa[i]=i,rox^=i; 70 while(m--){ 71 scanf("%s",c);int x,y,z; 72 if(c[0]=='A'){ 73 scanf("%d%d",&x,&y);t.link(x,y); 74 t.split(x=get(x),y=get(y)); 75 z=t.update(y);rox=(rox^x^y^z); 76 fa[x]=fa[y]=fa[z]=z; 77 } else if(c[0]=='Q'){ 78 scanf("%d",&x); 79 printf("%d\n",get(x)); 80 } else printf("%d\n",rox); 81 } return 0; 82 }