欢迎访问~原文出处——博客园-zhouzhendong
去博客园看该题解
题目传送门 - BZOJ2049
题意概括
有一堆点,一开始没有连边。
有3种操作,一种是连接某两个点,一种是断开某一条边。还有一种是询问两个点是否连通。
操作过程中保证整个图是森林。
点数<=10000,操作数<=200000
题解
LCT板子题。
对于询问,我们只需要access一下,然后splay一下,然后比较所在连通块的最左位置就可以了。
代码
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cmath>
using namespace std;
const int N=10005;
int n,m,fa[N],son[N][2],size[N],rev[N];
void pushup(int x){
size[x]=size[son[x][0]]+size[son[x][1]]+1;
}
bool isroot(int x){
return son[fa[x]][0]!=x&&son[fa[x]][1]!=x;
}
void pushdown(int x){
if (rev[x]){
rev[x]=0;
rev[son[x][0]]^=1;
rev[son[x][1]]^=1;
swap(son[x][0],son[x][1]);
}
}
void pushadd(int x){
if (!isroot(x))
pushadd(fa[x]);
pushdown(x);
}
int wson(int x){
return son[fa[x]][1]==x;
}
void rotate(int x){
if (isroot(x))
return;
int y=fa[x],z=fa[y],L=wson(x),R=L^1;
if (!isroot(y))
son[z][wson(y)]=x;
fa[x]=z;
fa[y]=x;
fa[son[x][R]]=y;
son[y][L]=son[x][R];
son[x][R]=y;
pushup(y);
pushup(x);
}
void splay(int x){
pushadd(x);
for (int y=fa[x];!isroot(x);rotate(x),y=fa[x])
if (!isroot(y))
rotate(wson(x)==wson(y)?y:x);
}
void access(int x){
int t=0;
while (x){
splay(x);
son[x][1]=t;
t=x;
x=fa[x];
}
}
void rever(int x){
access(x);
splay(x);
rev[x]^=1;
}
void link(int x,int y){
rever(x);
fa[x]=y;
}
void cut(int x,int y){
rever(x);
access(y);
splay(y);
fa[x]=son[y][0]=0;
}
int find(int x){
access(x);
splay(x);
while (son[x][0])
x=son[x][0];
return x;
}
int main(){
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++)
size[i]=1,rev[i]=fa[i]=son[i][0]=son[i][1]=0;
while (m--){
char op[10];
int a,b;
scanf("%s%d%d",op,&a,&b);
if (op[0]=='C')
link(a,b);
else if (op[0]=='D')
cut(a,b);
else
puts(find(a)==find(b)?"Yes":"No");
}
return 0;
}