BZOJ 3510 首都 (LCT)
题目大意:给你一颗树,边是一条一条连上去的
在连接过程中会存在询问,询问当前节点所在联通块(其实是一颗树)的重心是哪个节点
以及森林中所有树的重心的异或和
在做这道题之前,要先了解树的重心的一个性质:
两棵树合并时,新树的重心在合并后,原来两颗树的重心的两个节点构成的那条链上
了解了这条性质,思路就不难想了
当连接两个节点时,先寻找它们所在原树的重心,然后连接这两个节点,在取出两个原树重心那两个节点构成的那条链
每次寻找重心,连接节点,取出重心形成了链,复杂度约为
如果我们暴力跑这条链,最差的情况是每次合并时,两颗树都是等长的链,然后像线段树那样从下往上合并,合并次数最多是次,注意符合条件的重心最多只有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 }