• BZOJ2049 [Sdoi2008]Cave 洞穴勘测 LCT


    欢迎访问~原文出处——博客园-zhouzhendong

    去博客园看该题解


    题目传送门 - BZOJ2049


    题意概括

      有一堆点,一开始没有连边。

      有3种操作,一种是连接某两个点,一种是断开某一条边。还有一种是询问两个点是否连通。

      操作过程中保证整个图是森林。

      点数<=10000,操作数<=200000


    题解

      LCT板子题。

      对于询问,我们只需要access一下,然后splay一下,然后比较所在连通块的最左位置就可以了。


    代码

    #include <cstring>
    #include <cstdio>
    #include <cstdlib>
    #include <algorithm>
    #include <cmath>
    using namespace std;
    const int N=10005;
    int n,m,fa[N],son[N][2],size[N],rev[N];
    void pushup(int x){
    	size[x]=size[son[x][0]]+size[son[x][1]]+1;
    }
    bool isroot(int x){
    	return son[fa[x]][0]!=x&&son[fa[x]][1]!=x;
    }
    void pushdown(int x){
    	if (rev[x]){
    		rev[x]=0;
    		rev[son[x][0]]^=1;
    		rev[son[x][1]]^=1;
    		swap(son[x][0],son[x][1]);
    	}
    }
    void pushadd(int x){
    	if (!isroot(x))
    		pushadd(fa[x]);
    	pushdown(x);
    }
    int wson(int x){
    	return son[fa[x]][1]==x;
    }
    void rotate(int x){
    	if (isroot(x))
    		return;
    	int y=fa[x],z=fa[y],L=wson(x),R=L^1;
    	if (!isroot(y))
    		son[z][wson(y)]=x;
    	fa[x]=z;
    	fa[y]=x;
    	fa[son[x][R]]=y;
    	son[y][L]=son[x][R];
    	son[x][R]=y;
    	pushup(y);
    	pushup(x);
    }
    void splay(int x){
    	pushadd(x);
    	for (int y=fa[x];!isroot(x);rotate(x),y=fa[x])
    		if (!isroot(y))
    			rotate(wson(x)==wson(y)?y:x);
    }
    void access(int x){
    	int t=0;
    	while (x){
    		splay(x);
    		son[x][1]=t;
    		t=x;
    		x=fa[x];
    	}
    }
    void rever(int x){
    	access(x);
    	splay(x);
    	rev[x]^=1;
    }
    void link(int x,int y){
    	rever(x);
    	fa[x]=y;
    }
    void cut(int x,int y){
    	rever(x);
    	access(y);
    	splay(y);
    	fa[x]=son[y][0]=0;
    }
    int find(int x){
    	access(x);
    	splay(x);
    	while (son[x][0])
    		x=son[x][0];
    	return x;
    }
    int main(){
    	scanf("%d%d",&n,&m);
    	for (int i=1;i<=n;i++)
    		size[i]=1,rev[i]=fa[i]=son[i][0]=son[i][1]=0;
    	while (m--){
    		char op[10];
    		int a,b;
    		scanf("%s%d%d",op,&a,&b);
    		if (op[0]=='C')
    			link(a,b);
    		else if (op[0]=='D')
    			cut(a,b);
    		else
    			puts(find(a)==find(b)?"Yes":"No");
    	}
    	return 0;
    }
    

      

  • 相关阅读:
    STL逆序迭代器(reverse_iterator)
    STL容器之vector容器API(二)
    STL容器之vector容器巧用swap收缩空间
    STL容器之vector容器API(一)
    STL容器vector概念和注意事项(每次扩充都会重新开辟空间,释放原空间,即首元素地址会变一次)
    STL容器之string内存重定义
    STL容器之string与c_style类型转换
    STL容器之string插入和删除
    STL容器之string字串
    STL容器之string比较
  • 原文地址:https://www.cnblogs.com/zhouzhendong/p/BZOJ2049.html
Copyright © 2020-2023  润新知