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

输入

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

输出

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

样例输入

10 10 
Xor 
Q 1 
A 10 1 
A 1 4 
Q 4 
Q 10 
A 7 6 
Xor 
Q 7 
Xor 

样例输出

11 





2

题解

LCT维护子树信息

看了好几个小时的题解还是半懂不懂orz

先考虑连接两棵树

有两个性质

1.重心必在点数多的子树内

2.点数多的子树上重心移动的距离不超过点数少的子树的点数

然后就是连上之后,把这条路径拉出来,dfs一遍,枚举选哪一个点,然后判一下最优就好了

  1 // luogu-judger-enable-o2
  2 //minamoto
  3 #include<iostream>
  4 #include<cstdio>
  5 #include<algorithm>
  6 using std::swap;
  7 #define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
  8 char buf[1<<21],*p1=buf,*p2=buf;
  9 inline int read(){
 10     #define num ch-'0'
 11     char ch;bool flag=0;int res;
 12     while(!isdigit(ch=getc()))
 13     (ch=='-')&&(flag=true);
 14     for(res=num;isdigit(ch=getc());res=res*10+num);
 15     (flag)&&(res=-res);
 16     #undef num
 17     return res;
 18 }
 19 char obuf[1<<24],*o=obuf;
 20 inline void print(int x){
 21     if(x>9) print(x/10);
 22     *o++=x%10+48;
 23 }
 24 const int N=100005;
 25 int fa[N],st[N],sum[N],si[N],rev[N],ch[N][2],top,s;
 26 inline bool isroot(int x){return ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x;}
 27 inline void pushup(int x){sum[x]=sum[ch[x][0]]+sum[ch[x][1]]+si[x]+1;}
 28 inline void pushdown(int x){
 29     if(rev[x]){
 30         swap(ch[x][0],ch[x][1]);
 31         rev[ch[x][0]]^=1,rev[ch[x][1]]^=1;
 32         rev[x]=0;
 33     }
 34 }
 35 void rotate(int x){
 36     int y=fa[x],z=fa[y],d=ch[y][1]==x;
 37     if(!isroot(y)) ch[z][ch[z][1]==y]=x;
 38     fa[x]=z,fa[y]=x,fa[ch[x][d^1]]=y,ch[y][d]=ch[x][d^1],ch[x][d^1]=y,pushup(y);
 39 }
 40 void down(int x){
 41     if(!isroot(x)) down(fa[x]);
 42     pushdown(x);
 43 }
 44 void splay(int x){
 45     down(x);
 46     for(int y=fa[x],z=fa[y];!isroot(x);y=fa[x],z=fa[y]){
 47         if(!isroot(y))
 48         ((ch[y][1]==x)^(ch[z][1]==y))?rotate(x):rotate(y);
 49         rotate(x);
 50     }
 51     pushup(x);
 52 }
 53 void access(int x){
 54     for(int y=0;x;x=fa[y=x])
 55     splay(x),si[x]+=sum[ch[x][1]],si[x]-=sum[ch[x][1]=y],pushup(x);
 56 }
 57 void makeroot(int x){
 58     access(x),splay(x),rev[x]^=1;
 59 }
 60 int findroot(int x){
 61     access(x),splay(x),pushdown(x);
 62     while(ch[x][0]) pushdown(x=ch[x][0]);
 63     return x;
 64 }
 65 void split(int x,int y){
 66     makeroot(x),access(y),splay(y);
 67 }
 68 void link(int x,int y){
 69     split(x,y),fa[x]=y,si[y]+=sum[x],pushup(y);
 70 }
 71 void dfs(int x){
 72     pushdown(x);
 73     if(ch[x][0]) dfs(ch[x][0]);
 74     if(top>s) return;
 75     st[++top]=x;
 76     if(top>s) return;
 77     if(ch[x][1]) dfs(ch[x][1]);
 78 }
 79 int main(){
 80     //freopen("testdata.in","r",stdin);
 81     int n=read(),m=read(),res=0;
 82     for(int i=1;i<=n;++i) sum[i]=1,res^=i;
 83     while(m--){
 84         char c;
 85         while((c=getc())!='Q'&&c!='A'&&c!='X');
 86         switch(c){
 87             case 'A':{
 88                 int x=read(),y=read();
 89                 int tx=findroot(x),ty=findroot(y),ts;
 90                 res^=tx^ty;
 91                 splay(tx),splay(ty);
 92                 if(sum[tx]>sum[ty]||(sum[tx]==sum[ty]&&x<y)) swap(x,y),swap(tx,ty);
 93                 s=sum[tx],ts=sum[tx]+sum[ty],link(x,y),access(x),splay(ty);
 94                 top=0,dfs(ty);int r=ty;
 95                 for(int i=1;i<=top;++i){
 96                     splay(st[i]);int t=si[st[i]]+1+sum[ch[st[i]][1]];
 97                     if(ts-t<t||(ts-t==t&&st[i]<=r)) r=st[i];
 98                     else break;
 99                     /*枚举原重心到连接点之间的路径
100                     t表示枚举到某一点时另一棵子树的大小
101                     如果这棵子树大于另一边或那啥,更新答案
102                     否则之前的答案最优,直接退出*/
103                 }
104                 makeroot(r),res^=r;
105                 break;
106             }
107             case 'Q':{
108                 int x=read();
109                 print(findroot(x)),*o++='
';
110                 break;
111             }
112             case 'X':{
113                 print(res),*o++='
';
114                 break;
115             }
116         }
117     }
118     fwrite(obuf,o-obuf,1,stdout);
119     return 0;
120 }
原文地址:https://www.cnblogs.com/bztMinamoto/p/9418679.html