记录编号 412492 评测结果 AAAAAAAAAA
题目名称 [HZOI 2015]疯狂的重心 最终得分 100
用户昵称 GravatarFoolMike 是否通过 通过
代码语言 C++ 运行时间 0.315 s
提交时间 2017-06-09 16:24:12 内存使用 10.59 MiB
显示代码纯文本
#include<cstdio>
#include<algorithm>
using namespace std;
const int N=2e5+10;
int n,m,fa[N],s[N],son[N][2],v[N],pre[N],suf[N],prev[N],next[N];
bool root[N];
int apre[N],asuf[N];bool rev[N];
//v[x]表示子树x大小减去pre_child子树的大小 
//pre,suf表示一颗splay上v的前缀后缀和 
#define lc son[x][0]
#define rc son[x][1]
void flip(int x){
	swap(lc,rc);
	swap(prev[x],next[x]);
	swap(pre[x],suf[x]);
	swap(apre[x],asuf[x]);
	rev[x]^=1;
}
void add_pre(int x,int d){
	pre[x]+=d;
	apre[x]+=d;
}
void add_suf(int x,int d){
	suf[x]+=d;
	asuf[x]+=d;
}
void update(int x){
	s[x]=s[lc]+s[rc]+1;
}
void pushdown(int x){
	if (!x) return;
	if (rev[x]){
		if (lc) flip(lc);
		if (rc) flip(rc);
		rev[x]=0;
	}
	if (apre[x]){
		if (lc) add_pre(lc,apre[x]);
		if (rc) add_pre(rc,apre[x]);
		apre[x]=0;
	}
	if (asuf[x]){
		if (lc) add_suf(lc,asuf[x]);
		if (rc) add_suf(rc,asuf[x]);
		asuf[x]=0;
	}
}
void rot(int x){
	int y=fa[x],z=fa[y];
	bool b=(x==son[y][1]);
	fa[son[y][b]=son[x][!b]]=y;
	fa[son[x][!b]=y]=x;
	fa[x]=z;
	if (son[z][0]==y) son[z][0]=x;else
	if (son[z][1]==y) son[z][1]=x;
	root[x]=root[y];root[y]=0;
	update(y);update(x);
}
void splay(int x){
	pushdown(x);
	for (;!root[x];rot(x)){
		int y=fa[x],z=fa[y];
		pushdown(z);pushdown(y);pushdown(x);
		if (!root[y]) rot((x==son[y][0])==(y==son[z][0])?y:x);
	}
}
//suf[x]即子树x的大小 
int top(int x){
	for (;;x=lc){
		pushdown(x);
		if (!lc) break;
	}
	splay(x);
	return x;
}
void link_r(int x,int y){
	y=top(y);
	next[x]=y;
	prev[y]=x;
	v[x]-=suf[y];
	pre[x]-=suf[y];
	add_pre(y,pre[x]);
	root[rc=y]=0;
	update(x);
}
void cut_r(int x){
	int y=rc;
	if (!y) return;
	root[rc]=1;rc=0;
	update(x);
	y=top(y);
	next[x]=prev[y]=0;
	add_pre(y,-pre[x]);
	v[x]+=suf[y];
	pre[x]+=suf[y];
}
void access(int x){
	splay(x);
	cut_r(x);
	while (fa[x]){
		int y=fa[x];
		splay(y);
		cut_r(y);
		link_r(y,x);
		splay(x);
	}
}
void makeroot(int x){
	access(x);
	flip(x);
}
int T[N],size[N],ans;
int find(int x){return T[x]==x?x:T[x]=find(T[x]);}
int find(int x,int R){
	if (R>s[x]) return 0;
	while (1){
		pushdown(x);
		int i=s[lc]+1;
		if (R==i) break;
		if (R>i) R-=i,x=rc;else x=lc;
	}
	splay(x);
	return x;
}
int getsize(int x){
	if (!x) return 0;
	splay(x);
	return suf[x];
}
void solve(int x,int l,int r,int size){
	int mid=(l+r)>>1,pl=find(x,mid),pr=find(pl,mid+1);
	int sl=getsize(pl),sr=getsize(pr);
	if (sl*2>=size&&sr*2<=size) ans=min(ans,pl);
	if (l==r) return;
	if (sr*2<size) solve(pr,l,mid,size);
	if (sl*2>size) solve(pr,mid+1,r,size);
}
int main()
{
	freopen("G_Tree.in","r",stdin);
	freopen("G_Tree.out","w",stdout);
	scanf("%d%d",&n,&m);
	int xor_sum=0;
	for (int i=1;i<=n;i++){
		pre[i]=suf[i]=v[i]=size[i]=s[i]=root[i]=1;
		T[i]=i;
		xor_sum^=i;
	}
	char tp[10];int x,y;
	while (m--){
		scanf("%s",tp);
		if (tp[0]=='X') printf("%d\n",xor_sum);
		if (tp[0]=='Q'){
			scanf("%d",&x);
			printf("%d\n",find(x));
		}
		if (tp[0]=='A'){
			scanf("%d%d",&x,&y);
			int a=find(x),b=find(y);
			if (size[a]>size[b]) swap(x,y),swap(a,b);
			xor_sum^=a;
			xor_sum^=b;
			makeroot(y);
			fa[y]=x;
			access(x);
			v[x]+=suf[y];
			pre[x]+=suf[y];
			add_suf(x,suf[y]);
			makeroot(a);
			access(b);
			ans=n+1;
			solve(b,1,s[b],size[a]+size[b]);
			//getroot(b,size[a]+size[b]);
			//printf("new root is %d\n",ans);
			T[a]=T[b]=T[ans]=ans;
			size[ans]=size[a]+size[b];
			xor_sum^=ans;
		}
	}
	return 0;
}