[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);
  }
}
原文地址:https://www.cnblogs.com/dixiao/p/14736760.html