【lct】bzoj2049 [Sdoi2008]Cave 洞穴勘测

时间:2022-01-02 00:53:28

题意:维护一个动态并查集,支持加边,删边,维护两点连通性。

主要用到了 lct 的 Access FindRoot ChangeRoot link cut 操作。

#include<cstdio>
#include<iostream>
#include<stack>
#include<cstring>
#include<algorithm>
using namespace std;
#define maxn 10005
int fa[maxn],c[maxn][2],siz[maxn];
bool is_root[maxn],delta[maxn];
void Mark(int x){
    if(x){
        delta[x]^=1;
    }
}
void Maintain(int x)
{
    siz[x]=siz[c[x][0]]+siz[c[x][1]]+1;
}
void pushdown(int x){
    if(delta[x]){
        Mark(c[x][0]);
        Mark(c[x][1]);
        swap(c[x][0],c[x][1]);
        delta[x]=0;
    }
}
void Rotate(int x,bool flag)
{
    int y=fa[x];
    c[y][!flag]=c[x][flag];
    if(c[x][flag]){
        fa[c[x][flag]]=y;
    }
    if(fa[y] && c[fa[y]][c[fa[y]][1]==y]==y){
        c[fa[y]][c[fa[y]][1]==y]=x;
    }
    fa[x]=fa[y];
    c[x][flag]=y;
    fa[y]=x;
    if(is_root[y]){
        is_root[y]=0;
        is_root[x]=1;
    }
    Maintain(y);
    Maintain(x);
}
stack<int>st;
void Splay(int x)
{
    pushdown(x);
    if(!x || is_root[x]){
        return;
    }
    int U=x;
    while(!is_root[U]){
        st.push(U);
        U=fa[U];
    }
    st.push(U);
    while(!st.empty()){
        pushdown(st.top());
        st.pop();
    }
    int y;
    while(y=fa[x],(!is_root[x])){
        if(is_root[y]){
            Rotate(x,c[y][0]==x);
        }
        else{
            if((c[y][0]==x)==(c[fa[y]][0]==y)){
                Rotate(y,c[fa[y]][0]==y);
            }
            else{
                Rotate(x,c[y][0]==x);
                y=fa[x];
            }
            Rotate(x,c[y][0]==x);
        }
    }
    Maintain(x);
}
void Access(int x){
    int y;
    Splay(x);
    while(fa[x]){
        y=fa[x];
        Splay(y);
        Splay(x);
        if(c[y][1]){
            is_root[c[y][1]]=1;
        }
        is_root[x]=0;
        c[y][1]=x;
        Splay(x);
    }
    if(c[x][1]){
        is_root[c[x][1]]=1;
        c[x][1]=0;
    }
}
void ChangeRoot(int x){
    Access(x);
    Splay(x);
    Mark(x);
}
void cut(int x){
    Access(x);
    Splay(x);
    fa[c[x][0]]=0;
    if(c[x][0]){
        is_root[c[x][0]]=1;
    }
    c[x][0]=0;
}
void link(int x,int y){
    Access(x);
    Splay(x);
//  Mark(c[x][0]);
    Access(y);
    Splay(y);
    c[y][1]=x;
    fa[x]=y;
    is_root[x]=0;
}
int FindRoot(int x){
    Access(x);
    Splay(x);
    while(c[x][0]){
        x=c[x][0];
    }
    return x;
}
int n,m;
int main(){
//	freopen("bzoj2049.in","r",stdin);
	char op[10];
	int x,y;
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;++i){
		siz[i]=1;
		is_root[i]=1;
	}
	for(int i=1;i<=m;++i){
		scanf("%s%d%d",op,&x,&y);
		if(op[0]=='Q'){
			puts(FindRoot(x)==FindRoot(y) ? "Yes" : "No");
		}
		else if(op[0]=='C'){
			ChangeRoot(x);
			link(x,y);
		}
		else{
			if(FindRoot(x)==FindRoot(y)){
				ChangeRoot(x);
				cut(y);
			}
		}
	}
	return 0;
}