bzoj 3510 首都

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维护子树信息(+启发式合并)

这道题也真是强啊,分析了一会码了一会,结果却因为一个傻x错误坑了我一个多小时~

首先,在link时,要把点数少的连接到点数多的上(这其实不应该叫做启发式合并吧)

这样有什么好处?它有两个重要的性质:

1.合并后的重心一定在点数多的树之内,且在连接点到原重心的链上(因为如果在点数少的树之内,重心最后一段的移动路径一定对答案的贡献恒为负,一定不是最优解;而偏移方向不为到连接点方向的话对答案贡献也一定为负)

2.合并后的重心与原重心距离一定不超过点数少的树的点数(假设一个一个插入,偏移距离一定不超过1)

这就可以看出这样做的优势:性质1限定了重心移动的方向,性质2限定了重心移动的距离。

我们考虑:重心发生改变,把它移动的路径分为每次一条边的段,那么每一段对于答案的贡献一定是递减的,直到某一段对答案贡献为负则停止。

那么我们就可以模拟这个过程,将重心设为树根,每次把重心可能的移动路径拿出来,一个一个判断并处理。

嘴上说真简单

实际上,要动态维护子树大小,需要使用LCT维护子树信息。而在LCT中取出重心的移动路径并不是特别容易,需要求出Splay Tree的中序遍历,就要dfs整棵Splay Tree,并在超过范围时停止。

由于重心是固定的,因此将x合并到y上时不能makeroot(y),只能access(y),splay(y)

更复杂的问题是题目不是使用spj,而是强制要求有多个重心时需要选择编号较小的。所以还应该判断编号的影响。

最重要的是,findroot和dfs时都需要pushdown!一开始我在findroot时想起来了,结果到dfs时又忘了,因为这个sb错误zz了一个小时真是气。

 

 1 #include<bits/stdc++.h>
 2 using namespace std;  
 3 #define R register int 
 4 #define rep(i,a,b) for(R i=a;i<=b;i++)  
 5 #define Rep(i,a,b) for(R i=a;i>=b;i--)  
 6 #define ms(i,a)    memset(a,i,sizeof(a)) 
 7 #define gc()       getchar() 
 8 #define LL         long long 
 9 #define I          inline int 
10 #define pa         fa[x]
11 #define lc         ch[x][0]
12 #define rc         ch[x][1]  
13 template<class T>void read(T &x){
14     x=0; char c=0; 
15     while (!isdigit(c)) c=gc(); 
16     while (isdigit(c)) x=x*10+(c^48),c=gc();  
17 }
18 int const N=100000+3;  
19 int const M=200000+3;  
20 int n,m,top,st[N],ans,tp,sk[N]; 
21 int fa[N],ch[N][2],r[N],sum[N],sz[N];  
22 I get(int x){return ch[pa][1]==x;}
23 I isr(int x){return ch[pa][0]!=x && ch[pa][1]!=x; } 
24 I update(int x){sum[x]=sum[lc]+sum[rc]+sz[x]+1;} 
25 I con(int x,int y,int z){fa[x]=y;ch[y][z]=x;}
26 I rotate(int x){
27     int f=fa[x],g=fa[f],c=get(x),cc=get(f);  
28     if (!isr(f))  ch[g][cc]=x; fa[x]=g;  
29     con(ch[x][c^1],f,c);con(f,x,c^1);  
30     update(f); update(x);  
31 }
32 I pushd(int x){
33     if(!r[x]) return 0;  
34     swap(ch[lc][0],ch[lc][1]);
35     swap(ch[rc][0],ch[rc][1]);  
36     r[lc]^=1; r[rc]^=1; r[x]=0;  
37 }
38 I splay(int x){
39     top=0; int k=x; while (!isr(k)) st[++top]=k,k=fa[k]; st[++top]=k;  
40     while (top) pushd(st[top--]);  
41     for(;!isr(x);rotate(x)) if(!isr(pa))  rotate(get(x)==get(pa)? pa :x);  
42 }
43 I access(int x){
44     for(int y=0; x;  y=x,x=pa){
45         splay(x); 
46         sz[x]+=sum[rc]-sum[y];  
47         rc=y,update(x);  
48     }
49 }
50 I make(int x){
51     access(x); splay(x); r[x]^=1; swap(lc,rc);  
52 }
53 I find(int x){
54     access(x); splay(x);  
55     while (lc) x=lc;  
56     return x;  
57 }
58 I split(int x,int y){
59     make(x); access(y);  splay(y);  
60 }
61 I link(int x,int y){
62     make(x);   fa[x]=y; sz[y]+=sum[x]; update(y);  
63 }
64 void dfs(int x,int s){
65     if(tp>s) return ;  
66     pushd(x); 
67     if(lc) dfs(lc,s);  
68     sk[++tp]=x;  
69     if(rc) dfs(rc,s);  
70 }
71 int main(){
72     read(n); read(m);  
73     rep(i,1,n) ans^=i,sum[i]=1;  
74     while (m--){
75         char s[10];  
76         scanf("%s",s);  
77         if(s[0]=='X') printf("%d\n",ans); 
78         if(s[0]=='A'){
79             int x,y; read(x); read(y); 
80             int tx=find(x),ty=find(y);  
81             ans^=tx; ans^=ty; 
82             splay(tx); splay(ty);  
83             if(sum[tx]>sum[ty] || sum[tx]==sum[ty] && x<y)  swap(x,y),swap(tx,ty);  
84             int s=sum[tx], ts=sum[tx]+sum[ty];  
85             link(x,y);access(x); splay(ty);  
86             tp=0,dfs(ty,s); int r=ty;    
87             rep(i,1,tp){
88                 splay(sk[i]); int t=sz[sk[i]]+1+sum[ch[sk[i]][1]];   
89                 if(2*t>ts || 2*t==ts && r>=sk[i]) r=sk[i]; 
90             } 
91             make(r); ans^=r;  
92         }
93         if(s[0]=='Q') {
94             int x; read(x);  
95             printf("%d\n",find(x));
96         }
97     } 
98 }
View Code

 

posted @ 2019-01-16 11:12  zjxxcn  阅读(139)  评论(0编辑  收藏  举报