【题解】Luogu P3950 部落冲突

原题传送门

一开始先把树中每条边的两端连接

U操作:把u,v两个点连起来

C操作:把u,v两个点分开来

Q操作:判断在这个森林里u的根和v的根是否相等(是否连通)

#include <bits/stdc++.h>
#define N 300005
#define getchar nc
using namespace std;
inline char nc(){
    static char buf[100000],*p1=buf,*p2=buf; 
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++; 
}
inline int read()
{
    register int x=0,f=1;register char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
    return x*f;
}
inline void Swap(register int &a,register int &b)
{
    a^=b^=a^=b;
}
struct Link_Cut_Tree{
	int c[N][2],fa[N],top,q[N],rev[N];
	inline bool isroot(register int x)
	{
		return c[fa[x]][0]!=x&&c[fa[x]][1]!=x;
	}
	inline void pushdown(register int x)
	{
		if(rev[x])
		{
			int l=c[x][0],r=c[x][1];
			rev[l]^=1,rev[r]^=1,rev[x]^=1;
			Swap(c[x][0],c[x][1]);
		}
	}
	inline void rotate(register int x)
	{
		int y=fa[x],z=fa[y],l,r;
		l=c[y][0]==x?0:1;
		r=l^1;
		if(!isroot(y))
			c[z][c[z][0]==y?0:1]=x;
		fa[x]=z;
		fa[y]=x;
		fa[c[x][r]]=y;
		c[y][l]=c[x][r];
		c[x][r]=y;
	}
	inline void splay(register int x)
	{
		top=1;
		q[top]=x;
		for(register int i=x;!isroot(i);i=fa[i])
			q[++top]=fa[i];
		for(register int i=top;i;--i)
			pushdown(q[i]);
		while(!isroot(x))
		{
			int y=fa[x],z=fa[y];
			if(!isroot(y))
				rotate((c[y][0]==x)^(c[z][0]==y)?(x):(y));
			rotate(x);
		}
	}
	inline void access(register int x)
	{
		for(register int t=0;x;t=x,x=fa[x])
		{
			splay(x);
			c[x][1]=t;
		}
	}
	inline void makeroot(register int x)
	{
		access(x);
		splay(x);
		rev[x]^=1;
	}
	inline int findroot(register int x)
	{
		access(x);
		splay(x);
		while(c[x][0])
			x=c[x][0];
		return x;
	}
	inline void split(register int x,register int y)
	{
		makeroot(x);
		access(y);
		splay(y);
	}
	inline void cut(register int x,register int y)
	{
		split(x,y);
		c[y][0]=0;
		fa[x]=0;
	}
	inline void link(register int x,register int y)
	{
		makeroot(x);
		fa[x]=y;	
	}	
}T;
int n,m,cnt;
int a[N],b[N];
int main()
{
	n=read(),m=read();
	for(register int i=1;i<n;++i)
	{
		int u=read(),v=read();
		T.link(u,v);
	}
	while(m--)
	{
		char ch=getchar();
		while(ch!='Q'&&ch!='C'&&ch!='U')
			ch=getchar();
		if(ch=='Q')
		{
			int x=read(),y=read();
			puts(T.findroot(x)==T.findroot(y)?"Yes":"No");
		} 
		else if(ch=='C')
		{
			a[++cnt]=read(),b[cnt]=read();
			T.cut(a[cnt],b[cnt]);
		}
		else
		{
			int x=read();
			T.link(a[x],b[x]);
		}
	}
}
posted @ 2018-12-31 20:36  JSOI爆零珂学家yzhang  阅读(159)  评论(0编辑  收藏  举报