洛谷P2147 [SDOI2008] 洞穴勘测
P2147 [SDOI2008] 洞穴勘测
一看动态维护图连通性,吓到我了,还以为是那个黑题板子。
但原题目中有这样一句话
经过长期的艰苦卓绝的手工推算,辉辉发现一个奇怪的现象:无论通道怎么改变,任意时刻任意两个洞穴之间至多只有一条路径。
于是这便是一棵树了。
于是大力LCT。
完了。
#include<iostream>
using namespace std;
const int N = 1e5+100;
struct node{
int fa,son[2],val,sum,lazy;
}T[N];
inline void swap(int &x,int &y){
int tmp = x;
x = y,y = tmp;
}
bool Isroot(int u){
int f = T[u].fa;
return T[f].son[0]!=u && T[f].son[1]!=u;
}
void Pushup(int u){
T[u].sum = T[u].val ^ T[T[u].son[0]].sum ^ T[T[u].son[1]].sum;
}
void Reverse(int u){
if(!u) return;
swap(T[u].son[0],T[u].son[1]);
T[u].lazy ^= 1;
}
void Pushdown(int u){
if(T[u].lazy){
Reverse(T[u].son[0]),Reverse(T[u].son[1]);
T[u].lazy = 0;
}
}
void Push(int u){
if(!Isroot(u)) Push(T[u].fa);
Pushdown(u);
}
void Rotate(int u){
int f = T[u].fa,g = T[T[u].fa].fa;
int lorr = (T[f].son[1] == u);
//祖父与当前节点连边
if(!Isroot(f)) T[g].son[T[g].son[1]==f] = u;
T[u].fa = g;
//父亲与当前节点的儿子连边
T[f].son[lorr] = T[u].son[lorr^1];
if(T[u].son[lorr^1]) T[T[u].son[lorr^1]].fa = f;
//父亲与当前节点连边
T[u].son[lorr^1] = f;
T[f].fa = u;
Pushup(f);
}
void Splay(int u){
Push(u);
while(!Isroot(u)){
int f = T[u].fa,g = T[T[u].fa].fa;
if(!Isroot(f)) Rotate(((T[f].son[1]==u)==(T[g].son[1]==f))?f:u);
Rotate(u);
}
Pushup(u);
}
void Access(int u){
int child = 0;
while(u){
Splay(u);
T[u].son[1] = child;
Pushup(u);
child = u,u = T[u].fa;
}
}
void Makeroot(int u){
Access(u),Splay(u),Reverse(u);
}
void Split(int u,int v){
Makeroot(u),Access(v),Splay(v);
}
void Link(int u,int v){
Makeroot(u),T[u].fa = v;
}
void Cut(int u,int v){
Split(u,v);
if(T[v].son[0]!=u or T[u].son[1]) return;
T[u].fa = T[v].son[0] = 0;
Pushup(v);
}
int Findroot(int u){
Access(u),Splay(u);
while(T[u].son[0]) Pushdown(u),u = T[u].son[0];
return u;
}
int n,m,x,y;
string op;
int main(){
cin>>n>>m;
for(int i=1;i<=m;i++){
cin>>op>>x>>y;
if(op=="Query") cout<<(Findroot(x)==Findroot(y)?"Yes":"No")<<'\n';
if(op=="Connect"){
if(Findroot(x)!=Findroot(y)) Link(x,y);
}
if(op=="Destroy") Cut(x,y);
}
return 0;
}

浙公网安备 33010602011771号