1. 程式人生 > >bzoj 3510 首都 (LCT)

bzoj 3510 首都 (LCT)

print rev 心形 成了 2個 https urn 大小 zoj

洛谷P4299傳送門

題目大意:給你一顆樹,邊是一條一條連上去的

在連接過程中會存在詢問,詢問當前節點所在聯通塊(其實是一顆樹)的重心是哪個節點

以及森林中所有樹的重心的異或和

在做這道題之前,要先了解樹的重心的一個性質:

兩棵樹合並時,新樹的重心在合並後,原來兩顆樹的重心的兩個節點構成的那條鏈上

了解了這條性質,思路就不難想了

當連接兩個節點時,先尋找它們所在原樹的重心,然後連接這兩個節點,在取出兩個原樹重心那兩個節點構成的那條鏈

每次尋找重心,連接節點,取出重心形成了鏈,復雜度約為技術分享圖片

如果我們暴力跑這條鏈,最差的情況是每次合並時,兩顆樹都是等長的鏈,然後像線段樹那樣從下往上合並,合並次數最多是技術分享圖片

次,註意符合條件的重心最多只有2個,且子樹的大小符合單調性,當越過所有重心時,及時跳出循環防止卡常

總復雜度技術分享圖片

然而我還是喜聞樂見得被卡常了

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <algorithm>
  4 #define il inline
  5 #define N 200100
  6 using namespace std;
  7 
  8 int n,m,tp,num,xsum;
  9 int stk[N],que[N];
 10 
 11 struct LinkCutTree{
12 #define ls ch[x][0] 13 #define rs ch[x][1] 14 int fa[N],ch[N][2],sz[N],sum[N],rv[N]; 15 il int idf(int x){return ch[fa[x]][0]==x?0:1;} 16 il void rev(int x){swap(ls,rs),rv[x]^=1;} 17 il int isroot(int x){return (ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x)?1:0;} 18 il void
pushup(int x){sum[x]=sum[ls]+sum[rs]+sz[x]+1;} 19 il void pushdown(int x) 20 { 21 if(rv[x]){ 22 if(ls) rev(ls); 23 if(rs) rev(rs); 24 rv[x]^=1; 25 } 26 } 27 il void rot(int x) 28 { 29 int y=fa[x],ff=fa[y],px=idf(x),py=idf(y); 30 if(!isroot(y)) ch[ff][py]=x;fa[x]=ff; 31 ch[y][px]=ch[x][px^1],fa[ch[x][px^1]]=y; 32 ch[x][px^1]=y,fa[y]=x; 33 pushup(y),pushup(x); 34 } 35 void splay(int x) 36 { 37 int y=x;stk[++tp]=x; 38 while(!isroot(y)){stk[++tp]=fa[y],y=fa[y];} 39 while(tp){pushdown(stk[tp--]);} 40 while(!isroot(x)) 41 { 42 y=fa[x]; 43 if(isroot(y)) rot(x); 44 else if(idf(y)==idf(x)) rot(y),rot(x); 45 else rot(x),rot(x); 46 } 47 } 48 void access(int x){ 49 for(int y=0;x;y=x,x=fa[x]) 50 splay(x),sz[x]-=sum[y],sz[x]+=sum[ch[x][1]],ch[x][1]=y,pushup(x);} 51 il void mkroot(int x){access(x),splay(x),rev(x);} 52 il void split(int x,int y){mkroot(y),access(x),splay(x);} 53 il int findrt(int x){ 54 access(x),splay(x); 55 while(1){ 56 pushdown(x); 57 if(!ch[x][0])break; 58 x=ch[x][0];} 59 splay(x);return x; 60 } 61 void mid_dfs(int x) 62 { 63 pushdown(x); 64 if(ls) mid_dfs(ls); 65 que[++num]=x; 66 if(rs) mid_dfs(rs); 67 } 68 il void link(int x,int y) 69 { 70 int gx=findrt(x),gy=findrt(y); 71 xsum=xsum^gx^gy; 72 if(sum[gx]<sum[gy]) swap(x,y),swap(gx,gy); 73 split(x,y),fa[y]=x,sz[x]+=sum[y],pushup(x); 74 num=0,split(gy,gx),mid_dfs(gy); 75 int ma=sum[gy]/2,ans=0x3f3f3f3f; 76 for(int i=1;i<=num;i++){ 77 splay(que[i]); 78 if(sum[ch[que[i]][0]]<=ma&&sum[ch[que[i]][1]]<=ma&&que[i]<ans) 79 ans=que[i]; 80 if(sum[ch[que[i]][0]]>ma) break;} 81 mkroot(ans); 82 xsum^=ans; 83 } 84 #undef ls 85 #undef rs 86 }lct; 87 int gint() 88 { 89 int rett=0,fh=1;char c=getchar(); 90 while(c<0||c>9){if(c==-)fh=-1;c=getchar();} 91 while(c>=0&&c<=9){rett=(rett<<3)+(rett<<1)+c-0;c=getchar();} 92 return rett*fh; 93 } 94 void gchar(char str[]) 95 { 96 int p=0;char c=getchar(); 97 while(!((c>=A&&c<=Z)||(c>=a&&c<=z))){c=getchar();} 98 while((c>=A&&c<=Z)||(c>=a&&c<=z)){str[p++]=c;c=getchar();} 99 str[p]=\0; 100 } 101 102 int main() 103 { 104 scanf("%d%d",&n,&m); 105 for(int i=1;i<=n;i++) xsum^=i; 106 char q[10];int x,y; 107 for(int i=1;i<=m;i++) 108 { 109 gchar(q); 110 if(q[0]==A){ 111 x=gint(),y=gint(); 112 lct.link(x,y); 113 }else if(q[0]==Q){ 114 x=gint(); 115 printf("%d\n",lct.findrt(x)); 116 }else printf("%d\n",xsum); 117 } 118 return 0; 119 }

bzoj 3510 首都 (LCT)