[SDOI2008]洞穴勘测
\(LCT\)裸题。
不过区别于弹飞绵羊,这题要维护的树的形态,以及查询原根操作。
请记住,千万不要打错宏定义。
[SDOI2008]洞穴勘测
#include<iostream>
#include<cstdio>
#define ll long long
#define N 300005
ll f[N],c[N][2],v[N],r[N],st[N],s[N];
#define lc c[x][0]
#define rc c[x][1]
#define l(x) c[x][0]
#define r(x) c[x][1]
#define f(x) f[x]
#define R register int
#define I inline void
inline bool nroot(int x){return (l(f(x)) == x) || (r(f(x)) == x);}
inline void pushr(int x){std::swap(l(x),r(x));r[x] ^= 1;}
inline void pushdown(int x){
if(r[x]){
if(l(x))
pushr(l(x));
if(r(x))
pushr(r(x));
r[x] = 0;
}
}
inline void rotate(int x){
int y = f(x),z = f(y),k = c[y][1] == x,w = c[x][!k];
if(nroot(y))c[z][r(z) == y] = x;c[x][!k] = y,c[y][k] = w;
if(w)f(w) = y;f(y) = x;f(x) = z;
}
inline void splay(int x){
int y = x,z = 0;
st[++z] = y;
while(nroot(y))st[++z] = y = f(y);
while(z)pushdown(st[z--]);
while(nroot(x)){
y = f(x),z = f(y);
if(nroot(y))
rotate(((l(y) == x) ^ (l(z) == y)) ? x : y);
rotate(x);
}
}
inline void access(int x){
for(int y = 0;x;x = f(y = x))
splay(x),r(x) = y;
}
inline int findroot(int x){
access(x);splay(x);
while(l(x))pushdown(x),x = l(x);
splay(x);
return x;
}
inline void makeroot(int x){
access(x);splay(x);
pushr(x);
}
inline void split(int x,int y){
makeroot(x);
access(y);splay(y);
}
inline void link(int x,int y){
makeroot(x);
if(findroot(y) != x)
f(x) = y;
}
inline void cut(int x,int y){
makeroot(x);
if(findroot(y) == x && f(y) == x&&!l(y)){
f(y) = r(x) = 0;
}
}
ll n,m;
int main(){
scanf("%lld%lld",&n,&m);
while(m -- ){
char opt[10];
ll x,y;
scanf("%s%lld%lld",opt,&x,&y);
if(opt[0] == 'Q'){
if(findroot(x) == findroot(y))
puts("Yes");
else
puts("No");
}
if(opt[0] == 'C'){
link(x,y);
}
if(opt[0] == 'D')
cut(x,y);
}
}