zoukankan      html  css  js  c++  java
  • bzoj 2049 洞穴勘测

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    const int maxn=10010;
    int n,m;char s[10];
    
    struct node{
    	int c[maxn][2],f[maxn],rev[maxn];
    	bool isroot(int x){return (c[f[x]][0]!=x)&&(c[f[x]][1])!=x;}//
    	int which(int x){return c[f[x]][1]==x;}
    	void flip(int x){rev[x]^=1,swap(c[x][0],c[x][1]);}
    	void down(int x){if (rev[x]) flip(c[x][0]),flip(c[x][1]),rev[x]=0;}
    	void relax(int x){if (!isroot(x)) relax(f[x]);down(x);}
    	void rotate(int x){
    		int y=f[x],z=f[y],nx=which(x),ny=which(y);
    		f[c[x][!nx]]=y,c[y][nx]=c[x][!nx];
    		f[x]=z;if (!isroot(y)) c[z][ny]=x;
    		f[y]=x,c[x][!nx]=y;
    	}
    	void splay(int x){
    		relax(x);
    		while (!isroot(x)){
    			if (isroot(f[x])) rotate(x);
    			else if (which(x)==which(f[x])) rotate(f[x]),rotate(x);
    			else rotate(x),rotate(x);
    		}
    	}
    	void access(int x){for (int p=0;x;x=f[x]) splay(x),f[c[x][1]=p]=x,p=x;}//打通到根的路径。把x转到splay根,原本的实儿子断开,即断开splay中的右子树,与上面的splay合并时,因为深度比上面的深,直接接到右子树。 
    	void makeroot(int x){access(x),splay(x),flip(x);}//使x成为树的根 。先打通它到根的路径,它变成根以后,它到原根的路径倒过来,深度全部相反,在splay里进行翻转即可。 
    	int findroot(int x){//找到x所在树的根 
    		access(x);splay(x);
    		for (;c[x][0];x=c[x][0]) down(x);//深度最浅的就是根,所以找到splay最左边的点就是根 
    		return x;
    	}
    	void query(int a,int b){puts(findroot(a)==findroot(b)?"Yes":"No");}
    	void connect(int a,int b){makeroot(a),f[a]=b;}//连接a,b。把a变成它所在的树的根,在直接连到b即可
    	void destroy(int a,int b){makeroot(a),access(b),splay(b),f[a]=c[b][0]=0;}//断开a,b。把其中一个到根的路径打通,断开即可 
    }T;
    
    int main(){
    	scanf("%d%d",&n,&m);
    	for (int i=1,a,b;i<=m;i++){
    		scanf("%s%d%d",s,&a,&b);
    		if (s[0]=='Q') T.query(a,b);
    		else if (s[0]=='C') T.connect(a,b);
    		else T.destroy(a,b);
    	}
    	return 0;
    }

    这题是动态树入门题,所以操作也比较简单,就是支持删边,加边和询问两个点是否连通。

    删去边(a,b),只要把a变成根,把b到根的路径打通(access),把b转到splay的根,这时只有a的深度比b小,所以把b与splay中的左儿子断开即可。

    加上边(a,b),只要把a变成根,就可以把a接在b的下面了

    询问连通,可以转化为询问a,b所在树的的根是否相同,而树根在树中的深度一定是最小的,所以只要在splay中一直找左儿子,最左边的即是根。


  • 相关阅读:
    指针常量,常指针,指向常量的常指针(从我大一写的QQ空间迁移过来)
    关于负数的除法和余数的结果
    我爱Java系列---【案例:使用session存储验证码完成登录功能】
    我爱Java系列---【Java生成验证码案例】
    我爱Java系列---【Tomcat介绍及配置教程(附tomcat8.5.34下载文件,解压即可用)】
    我爱Java系列---【HTML基本标签】
    我爱Java系列---【原生JDBC】
    我爱Java系列---【mysql多表查询】
    我爱Java系列---【mysql查询DQL&多表关系】
    我爱Java系列---【mysql基础&约束】
  • 原文地址:https://www.cnblogs.com/thythy/p/5493603.html
Copyright © 2011-2022 走看看