Problem
Mean
要求编写一个数据结构,支持动态连边、删边和查询两点连通性。
保证两点间最多只有一条路径。
Analysis
LCT模板题。
(其实并查集更好些?)
借这题大致了解了一下LCT,顺便回顾了一下Splay。
LCT里的Splay略有不同于普通的Splay,也是需要特别注意的。
参考资料:Yang Zhe《SPOJ375 QTREE 解法的一些研究》
Code
#include<cstdio>
const int N=10005;
int n,m,x,y,f[N],son[N][2],tmp[N];
bool rev[N];
char s[10];
int read(){
char c;
while((c=getchar())<'0' || c>'9');
int x=c-'0';
while((c=getchar())>='0' && c<='9') x=x*10+c-'0';
return x;
}
bool isroot(int x){return !f[x] || son[f[x]][0]!=x && son[f[x]][1]!=x;}
void swap(int &x,int &y){int t=x;x=y,y=t;}
void revl(int x){if(!x) return;swap(son[x][0],son[x][1]);rev[x]^=1;}
void pb(int x){if(rev[x]) revl(son[x][0]),revl(son[x][1]),rev[x]=0;}
void rotate(int x){
int y=f[x],w=son[y][1]==x;
son[y][w]=son[x][w^1];
if(son[x][w^1]) f[son[x][w^1]]=y;
if(!isroot(y)) son[f[y]][son[f[y]][1]==y]=x;
f[x]=f[y];f[y]=x;son[x][w^1]=y;
}
void splay(int x){
int s=1,i=x,y;
tmp[1]=i;
while(!isroot(i)) tmp[++s]=i=f[i];
while(s) pb(tmp[s--]);
while(!isroot(x)){
y=f[x];
if(!isroot(y)){
if((son[f[y]][0]==y)^(son[y][0]==x)) rotate(x);
else rotate(y);
}
rotate(x);
}
}
void access(int x){for(int y=0;x;y=x,x=f[x]) splay(x),son[x][1]=y;}
int root(int x){access(x);splay(x);while(son[x][0]) x=son[x][0];return x;}
void makeroot(int x){access(x);splay(x);revl(x);}
void link(int x,int y){makeroot(x);f[x]=y;access(x);}
void cutf(int x){access(x);splay(x);f[son[x][0]]=0;son[x][0]=0;}
void cut(int x,int y){makeroot(x);cutf(y);}
int main(){
n=read(),m=read();
while(m--){
scanf("%s",s);
x=read(),y=read();
if(s[0]=='C') link(x,y);
else if(s[0]=='D') cut(x,y);
else if(root(x)!=root(y)) printf("No\n");
else printf("Yes\n");
}
return 0;
}