BZOJ2049 [Sdoi2008]Cave 洞穴勘测 LCT
欢迎访问~原文出处——博客园-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; }