到所有点距离和最小的点就是重心
因为只有link操作,我们可以考虑启发式合并,这样最多会有n log n次“插入一个叶子节点”操作
一棵树插入一个叶子节点之后,重心要么不变,要么向叶子的方向移动一条边,移动的条件是叶子所在的子树大小*2大于这棵树的大小(或者相等取编号小的)
用LCT维护子树大小即可
有关LCT维护子树信息的讲解可以看这里
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<cmath>
#include<algorithm>
#include<iomanip>
#include<vector>
#include<map>
#include<set>
#include<bitset>
#include<queue>
#include<stack>
using namespace std;
#define MAXN 100010
#define MAXM 1010
#define INF 1000000000
#define MOD 1000000007
#define eps 1e-8
#define ll long long
struct vec{
int to;
int fro;
};
vec mp[MAXN*2];
int tai[MAXN],cnt;
int fa[MAXN],son[MAXN][2],siz[MAXN],Siz[MAXN];
bool rev[MAXN];
int st[MAXN],tp;
int rt[MAXN];
int F[MAXN],SIZ[MAXN];
int xs;
int n,m;
void pt(){
int i;
for(i=1;i<=n;i++){
cerr<<son[i][0]<<' '<<son[i][1]<<' '<<fa[i]<<endl;
}
cerr<<"-------"<<endl;
}
inline void be(int x,int y){
mp[++cnt].to=y;
mp[cnt].fro=tai[x];
tai[x]=cnt;
}
inline void bde(int x,int y){
be(x,y);
be(y,x);
}
int FA(int x){
return F[x]==x?x:F[x]=FA(F[x]);
}
inline bool ir(int x){
return son[fa[x]][0]!=x&&son[fa[x]][1]!=x;
}
inline void cot(int x,int y,bool z){
if(x){
fa[x]=y;
}
if(y){
son[y][z]=x;
}
}
inline void torev(int x){
if(!x){
return ;
}
swap(son[x][0],son[x][1]);
rev[x]^=1;
}
inline void ud(int x){
siz[x]=siz[son[x][0]]+siz[son[x][1]]+1+Siz[x];
}
inline void pd(int x){
if(rev[x]){
torev(son[x][0]);
torev(son[x][1]);
rev[x]=0;
}
}
inline void rot(int x,bool z){
int xx=fa[x],xxx=fa[xx];
cot(son[x][z],xx,z^1);
if(ir(xx)){
fa[x]=xxx;
}else{
cot(x,xxx,son[xxx][1]==xx);
}
cot(xx,x,z);
ud(xx);
}
inline void apd(int x){
int i;
st[++tp]=x;
for(i=x;!ir(i);i=fa[i]){
st[++tp]=fa[i];
}
for(;tp;tp--){
pd(st[tp]);
}
}
void splay(int x){
apd(x);
while(!ir(x)){
int xx=fa[x],xxx=fa[xx];
if(ir(xx)){
rot(x,son[xx][0]==x);
}else{
bool z=son[xxx][0]==xx;
if(son[xx][z]==x){
rot(x,z^1);
rot(x,z);
}else{
rot(xx,z);
rot(x,z);
}
}
}
ud(x);
}
inline void acs(int x){
int t=0;
while(x){
splay(x);
Siz[x]+=siz[son[x][1]]-siz[t];
son[x][1]=t;
ud(x);
t=x;
x=fa[x];
}
}
inline void reboot(int x){
acs(x);
splay(x);
torev(x);
}
inline void link(int x,int y){
reboot(x);
reboot(y);
fa[x]=y;
Siz[y]+=siz[x];
ud(y);
reboot(rt[FA(y)]);
acs(x);
splay(rt[FA(y)]);
int S=siz[rt[FA(y)]];
int t=son[rt[FA(y)]][1];
pd(t);
while(son[t][0]){
t=son[t][0];
pd(t);
}
acs(t);
if((Siz[t]+1)*2>S||(Siz[t]+1)*2==S&&t<rt[FA(y)]){
xs^=rt[FA(y)];
xs^=t;
rt[FA(y)]=t;
}
}
void dfs(int x,int f){
int i,y;
son[x][0]=son[x][1]=fa[x]=rev[x]=0;
Siz[x]=0;
siz[x]=1;
link(x,f);
for(i=tai[x];i;i=mp[i].fro){
y=mp[i].to;
if(y!=f){
dfs(y,x);
}
}
}
int main(){
int i,x,y;
char o[5];
scanf("%d%d",&n,&m);
for(i=1;i<=n;i++){
F[i]=i;
rt[i]=i;
siz[i]=SIZ[i]=1;
xs^=i;
}
while(m--){
scanf("%s",o);
if(o[0]=='A'){
scanf("%d%d",&x,&y);
if(SIZ[FA(x)]>SIZ[FA(y)]){
swap(x,y);
}
SIZ[FA(y)]+=SIZ[FA(x)];
xs^=rt[FA(x)];
F[FA(x)]=FA(y);
dfs(x,y);
bde(x,y);
}
if(o[0]=='Q'){
scanf("%d",&x);
printf("%d\n",rt[FA(x)]);
}
if(o[0]=='X'){
printf("%d\n",xs);
}
}
return 0;
}
/*
9 9
A 1 2
A 3 4
A 5 4
A 4 6
A 1 7
A 1 8
A 1 4
A 3 9
Q 1
*/