洛谷P2147 [SDOI2008] 洞穴勘测 题解
题意:给定若干个点,动态连接(无向边),询问连通性
由于它有删边的操作,因此用并查集并不可行
于是想到LCT(?
由于LCT有 find_root()
操作
说明LCT确实可以动态判定连通性
那么就变成简单的模板题了(
代码如下
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define INF 0x3f3f3f3f3f3f3f3f
#define N (int)(1e4+5)
int n,Q;
namespace LCT
{
struct node
{
int ch[2],fa,tag;
}t[N];
#define isroot(x) ((t[t[x].fa].ch[0]!=x)&&(t[t[x].fa].ch[1]!=x))
void pushr(int x)
{
swap(t[x].ch[0],t[x].ch[1]);
t[x].tag^=1;
}
void push_down(int x)
{
if(t[x].tag)
{
if(t[x].ch[0])pushr(t[x].ch[0]);
if(t[x].ch[1])pushr(t[x].ch[1]);
t[x].tag=0;
}
}
void push_all(int x)
{
if(!isroot(x))push_all(t[x].fa);
push_down(x);
}
void rotate(int x)
{
int y=t[x].fa;
int z=t[y].fa;
int k=t[y].ch[1]==x;
if(!isroot(y))t[z].ch[t[z].ch[1]==y]=x;
t[x].fa=z;
t[y].ch[k]=t[x].ch[k^1];
t[t[x].ch[k^1]].fa=y;
t[x].ch[k^1]=y;
t[y].fa=x;
}
void splay(int x)
{
push_all(x);
while(!isroot(x))
{
int y=t[x].fa;
int z=t[y].fa;
if(!isroot(y))
(t[z].ch[1]==y)^(t[y].ch[1]==x)?rotate(x):rotate(y);
rotate(x);
}
}
void access(int x)
{
for(int y=0; x; y=x,x=t[x].fa)
splay(x),t[x].ch[1]=y;
}
void make_root(int x)
{
access(x);splay(x);
pushr(x);
}
int find_root(int x)
{
access(x);splay(x);
while(t[x].ch[0])push_down(x),x=t[x].ch[0];
splay(x);
return x;
}
void link(int x,int y)
{
make_root(x);
if(find_root(y)!=x)t[x].fa=y;
}
void cut(int x,int y)
{
make_root(x);
if(find_root(y)==x&&t[y].fa==x&&!t[y].ch[0])
t[y].fa=t[x].ch[1]=0;
}
}
signed main()
{
using namespace LCT;
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
cin >> n >> Q;
while(Q--)
{
string str;int x,y;
cin >> str >> x >> y;
if(str[0]=='Q')
{
make_root(x);
access(y);
if(find_root(y)!=x)cout << "No" << endl;
else cout << "Yes" << endl;
}
if(str[0]=='C') link(x,y);
if(str[0]=='D') cut(x,y);
}
return 0;
}