• BZOJ 3510: 首都 (lct)


    题面

    Description

    在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:询问当前所有国家首都编号的异或和。
    Input

    第一行是整数N,M,表示城市数和需要处理的信息数。
    接下来每行是一个信息,格式如题目描述(A、Q、Xor中的某一种)。
    Output

    输出包含若干行,为处理Q和Xor信息的结果。
    Sample Input
    10 10

    Xor

    Q 1

    A 10 1

    A 1 4

    Q 4

    Q 10

    A 7 6

    Xor

    Q 7

    Xor

    Sample Output
    11

    1

    1

    1

    2

    6

    2

    HINT

    对于100%的数据,2<=N<=100000,1<=M<=200000。

    解题思路

      (lct)维护子树信息。因为根据重心的性质,将两棵树拼起来,重心一定在这两棵树重心的连线上。还有一个性质就是当一棵树增加一个叶节点时,重心最多向叶节点方向移动(1)的距离,并且重心为根时的子树大小均小于树的大小(/2)。有了这几个性质,那么操作(1)就很简单了,我们用启发式合并,连接时(dfs) (siz)较小的子树,然后每次(link)较小的子树的每个节点和它的(father)(link)里处理重心,处理重心时,就先(makeroot)一下(siz)较大子树的根节点,然后(access)一下新加入的点。这样就将根节点到新加入节点的路径找见了,也就是确定了一下移动方向。然后在找一下根节点的后继,判断能否移动。还要用并查集维护一下每棵树的(siz)和根节点。

    代码

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cstdlib>
    
    using namespace std;
    const int MAXN = 100005;
    
    inline int rd(){
    	int x=0,f=1;char ch=getchar();
    	while(!isdigit(ch)) {f=ch=='-'?0:1;ch=getchar();}
    	while(isdigit(ch))  {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
    	return f?x:-x;
    }
    
    int n,m,ch[MAXN][2],fa[MAXN],SIZ[MAXN];
    int siz[MAXN],Siz[MAXN],Xor,F[MAXN],rt[MAXN];
    int to[MAXN<<1],nxt[MAXN<<1],head[MAXN],cnt;
    bool rev[MAXN];
    
    inline void add(int bg,int ed){
    	to[++cnt]=ed,nxt[cnt]=head[bg],head[bg]=cnt;
    }
    
    int Find(int x){
    	if(F[x]==x) return x;
    	return F[x]=Find(F[x]);
    }
    
    inline bool isroot(int x){
    	return (x!=ch[fa[x]][0] && x!=ch[fa[x]][1]);
    }
    
    inline bool check(int x){
    	return (x==ch[fa[x]][1]);
    }
    
    inline void pushup(int x){
    	siz[x]=siz[ch[x][0]]+siz[ch[x][1]]+Siz[x]+1;
    }
    
    inline void pushdown(int x){
    	if(rev[x]){
    		swap(ch[x][0],ch[x][1]);
    		if(ch[x][0]) rev[ch[x][0]]^=1;
    		if(ch[x][1]) rev[ch[x][1]]^=1;
    		rev[x]^=1;
    	}
    }
    
    void pd(int x){
    	if(fa[x]) pd(fa[x]);pushdown(x);
    }
    
    inline void rotate(int x){
    	int y=fa[x],z=fa[y];bool chk=check(x);
    	if(!isroot(y)) ch[z][check(y)]=x;
    	ch[y][chk]=ch[x][chk^1];fa[ch[x][chk^1]]=y;
    	ch[x][chk^1]=y;fa[y]=x;fa[x]=z;pushup(y);pushup(x);
    }
    
    inline void splay(int x){
    	pd(x);
    	for(;!isroot(x);rotate(x))
    		if(!isroot(fa[x])) rotate(check(fa[x])==check(x)?fa[x]:x);
    }
    
    inline void access(int x){
    	for(int y=0;x;y=x,x=fa[x]){
    		splay(x);if(y) Siz[x]-=siz[y];
    		if(ch[x][1]) Siz[x]+=siz[ch[x][1]];
    		ch[x][1]=y;pushup(x);	
    	}
    }
    
    inline void makeroot(int x){
    	access(x);splay(x);rev[x]^=1;
    }
    
    inline void link(int x,int y){
    	makeroot(x);makeroot(y);
    	fa[x]=y;Siz[y]+=siz[x];pushup(y);int zz=Find(y);
    	makeroot(rt[zz]);access(x);splay(rt[zz]);
    	int S=siz[rt[zz]],T=ch[rt[zz]][1];pushdown(T);
    	while(ch[T][0]) T=ch[T][0],pushdown(T);
    	access(T);
    	if((Siz[T]+1)*2>S || (((Siz[T]+1)*2==S) && (T<rt[zz]))) {
    		Xor^=rt[zz];Xor^=T;rt[zz]=T;
    	} 
    }
    
    void dfs(int x,int y){
    	ch[x][0]=ch[x][1]=fa[x]=rev[x]=0;Siz[x]=0;siz[x]=1;
    	link(x,y);int u;
    	for(int i=head[x];i;i=nxt[i]){
    		u=to[i];if(u==y) continue;
    		dfs(u,x);
    	}
    }
    
    int main(){
    	n=rd(),m=rd();char s[5];int x,y,u,v;
    	for(int i=1;i<=n;i++) siz[i]=SIZ[i]=1,Xor^=i,F[i]=rt[i]=i;
    	while(m--){
    		scanf("%s",s+1);
    		if(s[1]=='A') {
    			x=rd(),y=rd();
    			u=Find(x);v=Find(y);
    			if(SIZ[u]>SIZ[v]) swap(u,v),swap(x,y);
    			F[u]=v;SIZ[v]+=SIZ[u];Xor^=rt[u];
    			dfs(x,y);add(x,y);add(y,x);
    		}
    		if(s[1]=='Q') x=rd(),printf("%d
    ",rt[Find(x)]);
    		if(s[1]=='X') printf("%d
    ",Xor);
    	}
    	return 0;
    }
    
  • 相关阅读:
    Python爬虫入门教程 45-100 Charles抓取兔儿故事-下载小猪佩奇故事-手机APP爬虫部分
    Python爬虫入门教程 44-100 Charles的安装与使用-手机APP爬虫部分
    Python爬虫入门教程 42-100 爬取儿歌多多APP数据-手机APP爬虫部分
    Python爬虫入门教程 43-100 百思不得姐APP数据-手机APP爬虫部分
    Python爬虫入门教程 41-100 Fiddler+夜神模拟器+雷电模拟器配置手机APP爬虫部分
    Python爬虫入门教程 40-100 博客园Python相关40W博客抓取 scrapy
    Python爬虫入门教程 39-100 天津市科技计划项目成果库数据抓取 scrapy
    Python爬虫入门教程 38-100 教育部高校名单数据爬虫 scrapy
    Python爬虫入门教程 37-100 云沃客项目外包网数据爬虫 scrapy
    Python爬虫入门教程 36-100 酷安网全站应用爬虫 scrapy
  • 原文地址:https://www.cnblogs.com/sdfzsyq/p/10034285.html
Copyright © 2020-2023  润新知