题面
题意:一个森林,两个操作,①连边。②问一个连通块的重心。
由于它只有连边,所以我们可以搞个类似启发式的东西
考虑一个小树的u和一棵大树的v连边
重心一定打大树里面
设大树的重心为ro
则新的重心一定在ro到v的路径上
并且移动的步数不会超过小树的siz
用LCT维护子树大小
Evert(ro),Access(v)后
在Splay上拎出一条长为小树的siz的链,在上面一步一步地走
就可以找到新的重心
这样就是nlogn的了。
我的程序强行多个log
为了省常数就把重心记在了并查集上
#include <iostream>
#include <fstream>
#include <algorithm>
#include <cmath>
#include <ctime>
#include <cstdio>
#include <cstdlib>
#include <cstring>
using namespace std;
#define mmst(a, b) memset(a, b, sizeof(a))
#define mmcp(a, b) memcpy(a, b, sizeof(b))
typedef long long LL;
const int N=300300;
void read(int &hy)
{
hy=0;
char cc=getchar();
while(cc<'0'||cc>'9')
cc=getchar();
while(cc>='0'&&cc<='9')
{
hy=(hy<<3)+(hy<<1)+cc-'0';
cc=getchar();
}
}
int n,q,u,v;
int fa[N],root[N],ans;
int find(int x)
{
if(fa[x]!=x)
fa[x]=find(fa[x]);
return fa[x];
}
struct tree
{
int other,sum;
bool flip;
tree *c[2],*pp,*f;
void sc(tree *x,int d){(c[d]=x)->f=this;}
int d(){return f->c[1]==this;}
}nil[N],*ro[N];
void up(tree *x)
{
x->sum=x->c[0]->sum+x->c[1]->sum+x->other;
}
void down(tree *x)
{
if(x->flip)
{
swap(x->c[0],x->c[1]);
x->c[0]->flip^=1;
x->c[1]->flip^=1;
x->flip=0;
}
}
void work(tree *x)
{
if(x->f!=nil)
work(x->f);
down(x);
}
void zig(tree *x)
{
tree *y=x->f;
int d=x->d();
y->sc(x->c[!d],d);
if(y->f!=nil)
y->f->sc(x,y->d());
else
x->f=nil;
x->sc(y,!d);
up(y);
up(x);
x->pp=y->pp;
y->pp=nil;
}
void splay(tree *x)
{
work(x);
for(tree *y;x->f!=nil;)
{
y=x->f;
if(y->f!=nil)
(x->d() ^ y->d()) ? zig(x) : zig(y);
zig(x);
}
}
void Access(tree *x)
{
tree *y=nil;
while(x!=nil)
{
splay(x);
if(x->c[1]!=nil)
{
x->c[1]->f=nil;
x->c[1]->pp=x;
x->other+=x->c[1]->sum;
};
x->c[1]=y;
if(y!=nil)
y->f=x,x->other-=y->sum;
up(x);
y->pp=nil;
y=x;
x=x->pp;
}
}
void Evert(tree *x)
{
Access(x);
splay(x);
x->flip=1;
}
tree *nex(tree *x)
{
x=x->c[1];
if(x==nil)
return x;
down(x);
while(x->c[0]!=nil)
{
x=x->c[0];
down(x);
}
splay(x);
return x;
}
int main()
{
nil->c[0]=nil->c[1]=nil->f=nil->pp=nil;
cin>>n>>q;
for(int i=1;i<=n;i++)
{
root[i]=fa[i]=i;
ans^=i;
nil[i]=nil[0];
nil[i].other=1;
ro[i]=nil+i;
}
while(q--)
{
char cc[10];
scanf("%s",cc);
if(cc[0]=='X')
printf("%d\n",ans);
else
if(cc[0]=='Q')
{
read(u);
printf("%d\n",root[find(u)]);
}
else
{
read(u);
read(v);
int X=find(u),Y=find(v);
ans^=root[X];
ans^=root[Y];
Evert(ro[u]);
splay(ro[u]);
Evert(ro[v]);
splay(ro[v]);
if(ro[u]->sum<ro[v]->sum)
swap(u,v),swap(X,Y);
ro[v]->pp=ro[u];
ro[u]->other+=ro[v]->sum;
up(ro[u]);
int all=ro[u]->sum;
tree *Violet=ro[root[X]];
Evert(Violet);
Access(ro[v]);
splay(Violet);
while(1)
{
int tu=Violet->c[1]->sum;
tree *hy=nex(Violet);
if(hy==nil)
break;
if(tu*2>all||tu*2==all&&hy<Violet)
Violet=hy;
else
break;
}
root[find(u)]=Violet-nil;
fa[Y]=X;
ans^=root[find(u)];
}
}
return 0;
}