[洛谷P4299] 首都
还是维护子树信息。
但是这里多了一个找重心的操作。
这里有一个关于树重心的结论,据说可以用反证法证明。反正我不会证
就是:新的重心一定在原来两个重心之间的那条树链上。
这样我们逐步缩小搜索范围,就可以很快地找到新树的重心了。
另外,每次找重心太慢了,用并查集维护一下每个点所在的树重心。
其他的就没什么特别了。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #define id(x) (s[f[x]][1]==x) 5 using namespace std; 6 7 int n,m; 8 int s[100005][2],f[100005]; 9 int sz[100005],szi[100005]; 10 int rev[100005],rt[100005]; 11 int ff[100005]; 12 13 int findfa(int x) 14 { 15 if(x==ff[x])return x; 16 ff[x]=findfa(ff[x]); 17 return ff[x]; 18 } 19 20 void pushup(int p) 21 { 22 sz[p]=sz[s[p][0]]+sz[s[p][1]]+szi[p]+1; 23 } 24 25 void reverse(int p) 26 { 27 swap(s[p][0],s[p][1]); 28 rev[p]^=1; 29 } 30 31 void pushdown(int p) 32 { 33 if(!rev[p])return; 34 reverse(s[p][0]); 35 reverse(s[p][1]); 36 rev[p]=0; 37 } 38 39 void rotate(int p) 40 { 41 int k=id(p); 42 int fa=f[p]; 43 if(rt[fa])rt[p]=1,rt[fa]=0; 44 else s[f[fa]][id(fa)]=p; 45 s[fa][k]=s[p][!k]; 46 s[p][!k]=fa; 47 f[p]=f[fa]; 48 f[fa]=p; 49 f[s[fa][k]]=fa; 50 pushup(fa); 51 pushup(p); 52 } 53 54 void down(int p) 55 { 56 if(!rt[p])down(f[p]); 57 pushdown(p); 58 } 59 60 void splay(int p) 61 { 62 down(p); 63 while(!rt[p]) 64 { 65 int fa=f[p]; 66 if(rt[fa]) 67 { 68 rotate(p); 69 return; 70 } 71 if(id(p)^id(fa))rotate(p); 72 else rotate(fa); 73 rotate(p); 74 } 75 } 76 77 void access(int p) 78 { 79 int son=0; 80 while(p) 81 { 82 splay(p); 83 szi[p]+=sz[s[p][1]]; 84 rt[s[p][1]]=1,rt[son]=0; 85 s[p][1]=son; 86 szi[p]-=sz[s[p][1]]; 87 pushup(p); 88 son=p,p=f[p]; 89 } 90 } 91 92 void mtr(int p) 93 { 94 access(p); 95 splay(p); 96 reverse(p); 97 } 98 99 void isolate(int x,int y) 100 { 101 mtr(x); 102 access(y); 103 splay(y); 104 } 105 106 int nueva(int p) 107 { 108 int l,r,sum=sz[p]>>1,tot=sz[p]&1,lsum=0,rsum=0,ng=n+1,nl,nr; 109 while(p) 110 { 111 pushdown(p); 112 l=s[p][0],r=s[p][1]; 113 nl=sz[l]+lsum,nr=sz[r]+rsum; 114 if(nl<=sum&&nr<=sum) 115 { 116 if(tot) 117 { 118 ng=p; 119 break; 120 }else 121 if(ng>p)ng=p; 122 } 123 if(nl<nr)lsum+=sz[l]+szi[p]+1,p=r; 124 else rsum+=sz[r]+szi[p]+1,p=l; 125 } 126 splay(ng); 127 return ng; 128 } 129 130 int xsum; 131 132 int main() 133 { 134 scanf("%d%d",&n,&m); 135 for(int i=1;i<=n;i++) 136 { 137 sz[i]=rt[i]=1; 138 ff[i]=i; 139 xsum^=i; 140 } 141 for(int i=1;i<=m;i++) 142 { 143 char op[5]; 144 scanf("%s",op+1); 145 if(op[1]=='A') 146 { 147 int x,y; 148 scanf("%d%d",&x,&y); 149 isolate(x,y); 150 f[x]=y; 151 szi[y]+=sz[x]; 152 pushup(y); 153 x=findfa(x),y=findfa(y); 154 isolate(x,y); 155 int ng=nueva(y); 156 xsum=xsum^x^y^ng; 157 ff[x]=ff[y]=ff[ng]=ng; 158 } 159 if(op[1]=='Q') 160 { 161 int x; 162 scanf("%d",&x); 163 printf("%d\n",findfa(x)); 164 } 165 if(op[1]=='X')printf("%d\n",xsum); 166 } 167 return 0; 168 }