zoukankan      html  css  js  c++  java
  • bzoj3510: 首都

    题面:在X星球上有N个国家,每个国家占据着X星球的一座城市。由于国家之间是敌对关系,所以不同国家的两个城市是不会有公路相连的。 
    X星球上战乱频发,如果A国打败了B国,那么B国将永远从这个星球消失,而B国的国土也将归A国管辖。A国国王为了加强统治,会在A国和B国之间修建一条公路,即选择原A国的某个城市和B国某个城市,修建一条连接这两座城市的公路。 
    同样为了便于统治自己的国家,国家的首都会选在某个使得其他城市到它距离之和最小的城市,这里的距离是指需要经过公路的条数,如果有多个这样的城市,编号最小的将成为首都。 
    现在告诉你发生在X星球的战事,需要你处理一些关于国家首都的信息,具体地,有如下3种信息需要处理: 
    1、A x y:表示某两个国家发生战乱,战胜国选择了x城市和y城市,在它们之间修建公路(保证其中城市一个在战胜国另一个在战败国)。 
    2、Q x:询问当前编号为x的城市所在国家的首都。 

    3、Xor:询问当前所有国家首都编号的异或和。 



    思路:动态树维护重心,保证每个国家的树根是重心以回答第二个问题,重要的是合并操作。对于合并操作,暴力拆小树,一个一个接到大树上,因为只会合并,所以所有操作总共只会接O(n)个点。接完后,把小树重心到大树重心的路径access,新树的重心一定在这条路径上,我们只要把重心即根向小树方向暴力移动即可,移动时要记得更新size和第3问的答案。这样暴力移动只会移动不超过小树大小步,所以所有操作总共只会移动O(n)次,总复杂度就有保证了。


    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define ls c[x][0]
    #define rs c[x][1]
    using namespace std;
    const int maxn=100010,maxm=400010;
    int pre[maxm],now[maxn],son[maxm],tot,n,m,vis[maxn],q[maxn<<1],ans;char op[5],ch;
    void ins(int a,int b){pre[++tot]=now[a],now[a]=tot,son[tot]=b;}
    
    void read(int &x){
    	for (ch=getchar();!isdigit(ch);ch=getchar());
    	for (x=0;isdigit(ch);ch=getchar()) x=x*10+ch-'0';
    }
    
    struct LCT{
    	int size[maxn],c[maxn][2],fa[maxn],add[maxn];
    	bool isroot(int x){return c[fa[x]][0]!=x&&c[fa[x]][1]!=x;}
    	int which(int x){return c[fa[x]][1]==x;}
    	void update(int x){}
    	void inc(int x,int v){size[x]+=v,add[x]+=v;}
    	void down(int x){if (add[x]) inc(ls,add[x]),inc(rs,add[x]),add[x]=0;}
    	void relax(int x){if (!isroot(x)) relax(fa[x]);down(x);}
    	void rotate(int x){
    		int y=fa[x],z=fa[y],nx=which(x),ny=which(y);
    		fa[c[x][!nx]]=y,c[y][nx]=c[x][!nx];
    		fa[x]=z;if (!isroot(y)) c[z][ny]=x;
    		fa[y]=x,c[x][!nx]=y;update(y);
    	}
    	void splay(int x){
    		relax(x);
    		while (!isroot(x)){
    			if (isroot(fa[x])) rotate(x);
    			else if (which(x)==which(fa[x])) rotate(fa[x]),rotate(x);
    			else rotate(x),rotate(x);
    		}
    		update(x);
    	}
    	void access(int x){for (int p=0;x;p=x,x=fa[x]) splay(x),fa[c[x][1]=p]=x,update(x);}
    	int findroot(int x){
    		access(x),splay(x);
    		for (;ls;x=ls) down(x);
    		return x;
    	}
    	int next(int x){
    		x=rs;for (;ls;x=ls);
    		if (x) splay(x);return x;
    	}
    	void bfs(int x,int f){//拆完小树接到大树上,更新新树的size 
    		int tail=1;fa[q[1]=x]=f,size[x]=1,ls=rs=add[x]=0,vis[x]=m;//小树暴力重构了,连边的点x没有fa了,所以不用makeroot(x);
    		for (int head=1;head<=tail;head++)
    			for (int y=now[x=q[head]];y;y=pre[y])
    				if (vis[son[y]]!=m)
    					fa[q[++tail]=son[y]]=x,c[son[y]][0]=c[son[y]][1]=add[son[y]]=0,size[son[y]]=1,vis[son[y]]=m;
    		for (int i=tail;i;i--) x=q[i],size[fa[x]]+=size[x];
    	}
    	void merge(int x,int y){
    		int fx=findroot(x),fy=findroot(y);
    		if (fx==fy) return;
    		if (size[fx]<size[fy]) swap(x,y),swap(fx,fy);//把小的合并到大的 
    		ans^=fy,bfs(y,x),ins(x,y),ins(y,x);//去除小树对答案的影响 
    		access(x),splay(x),inc(ls,size[y]),access(fy),splay(fx);//x到大树的根的路径上的点size都要加上小树的size 
    		for (;;){//寻找新树的重心,保证每棵树的根的是重心。从原重心向刚接起的小树方向不断移动,直到找到新重心。
    			int z=next(fx);if (!z) break;
    			if (size[z]*2>size[fx]||(size[z]*2==size[fx]&&z<fx)){
    				c[z][0]=0,swap(size[z],size[fx]),size[fx]=size[z]-size[fx];
    				//把新找到更靠近重心的点设为根
    				//于是没有比它深度更浅的点,更新size
    				ans^=z^fx,fx=z;//更新答案
    			}
    			else break;
    		}
    	}
    }T;
    
    int main(){
    	scanf("%d%d",&n,&m);
    	for (int i=1;i<=n;i++) T.size[i]=1,ans^=i;
    	while (m--){
    		scanf("%s",op);int x,y;
    		if (op[0]=='X') printf("%d
    ",ans);
    		else if (op[0]=='Q') read(x),printf("%d
    ",T.findroot(x));
    		else read(x),read(y),T.merge(x,y);
    	}
    	return 0;
    }
    



  • 相关阅读:
    不规范的json文档 转化成 java 对象的处理
    财经接口
    Back-off pulling image "registry.access.redhat.com/rhel7/pod-infrastructure:latest
    VMware Workstation 14 Pro永久激活密钥
    Angular2入门:TypeScript的装饰器
    Angular2入门:TypeScript的模块
    Angular2入门:TypeScript的类
    51nod“省选”模测第二场 B 异或约数和(数论分块)
    51nod1238 最小公倍数之和 V3(莫比乌斯反演)
    cf1139D. Steps to One(dp)
  • 原文地址:https://www.cnblogs.com/thythy/p/5493588.html
Copyright © 2011-2022 走看看