bzoj3510首都 LCT维护子树信息+启发式合并
2017-10-19 09:09
405 查看
3510: 首都
Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 213 Solved: 82
[Submit][Status][Discuss]
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 10Xor
Q 1
A 10 1
A 1 4
Q 4
Q 10
A 7 6
Xor
Q 7
Xor
Sample Output
111
1
1
2
6
2
HINT
对于100%的数据,2<=N<=100000,1<=M<=200000。Source
呼呼,好难!!(蒟蒻伤不起)启发式合并+LCT维护子树信息
首先讲讲启发式合并
听起来很高大上,实际很暴力
就是,每次新加一个节点,就把整棵树重新添加一遍(在LCT中)
据说只要把小的合到大的里面,就可以实现log
特别神奇有木有。
啊啦啊啦,别看现在几句话,已经要多开好几个数组了(敲黑板!)
1.FA[]记录并查集2.SIZ[]记录并查集大小3.struct edge用来建出真正的树
然后合并的时候,就把小的树一个一个添加到大的树中就可以了
代码看看:
if(opt == 'A') {
int x = read(), y = read(), fx = find(x), fy = find(y);
if(sz[fx] > sz[fy]) swap(x, y), swap(fx, fy);
sz[fy] += sz[fx];
ans ^= rt[fx]; F[fx] = fy;
dfs(x, y);
adds(x, y);
}
void dfs(int x, int f) { ch[x][0] = ch[x][1] = fa[x] = rev[x] = 0; isiz[x] = 0; siz[x] = 1; Link(x, f); for(int i = pre[x]; i; i = e[i].next) if(e[i].to != f) dfs(e[i].to, x); }然后,就是LCT维护子树信息了
首先看看这个blog,说的贼好,%%%:戳这里
众所周知(如果这句话伤害到了您,请原谅),如果一个节点的某个子树大小的两倍大于整棵树的大小,那么这颗子树的根节点一定比原节点更优。
所以在暴力插树Link时“顺便”移动重心就可以了。就可以了
代码:
void Link(int p, int g) { makeroot(p); makeroot(g); fa[p] = g; isiz[g] += siz[p]; update(g); int fg = find(g); makeroot(rt[fg]); Access(p); Splay(rt[fg]); int S = siz[rt[fg]]; int t = ch[rt[fg]][1]; push_down(t); while(ch[t][0]) { t = ch[t][0]; push_down(t); } Access(t); if(((isiz[t] + 1) << 1) > S || ((isiz[t] + 1) << 1) == S && t < rt[fg]) { ans ^= rt[fg] ^ t; rt[fg] = t; } }其他都是LCT套路和细节与细节与细节不解释了
全代码:
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#include<cmath>
#define maxn 220000
#define ls ch[p][0]
#define rs ch[p][1]
using namespace std;
int read() {
char ch = getchar(); int x = 0, f = 1;
while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
while(ch >= '0' && ch <= '9') {x = x * 10 - '0' + ch; ch = getchar();}
return x * f;
}
int tot, pre[maxn];
struct edge {
int to, next;
void add(int u, int v) {
to = v; next = pre[u];
pre[u] = tot;
}
}e[maxn << 2];
void adds(int u, int v) {
e[++tot].add(u, v);
e[++tot].add(v, u);
}
int ch[maxn][2], fa[maxn], siz[maxn], isiz[maxn], sz[maxn];
bool rev[maxn];
int F[maxn], rt[maxn], st[maxn], n, m, ans, top;
bool wh(int p) {return ch[fa[p]][1] == p;}
bool Isroot(int p) {return ch[fa[p]][0] != p && ch[fa[p]][1] != p;}
void update(int p) {siz[p] = siz[ls] + siz[rs] + isiz[p] + 1;}
void push_down(int p) {
if(rev[p]) {
if(ls) rev[ls] ^= 1; if(rs) rev[rs] ^= 1;
rev[p] ^= 1; swap(ls, rs);
}
}
void push_up(int p) {
st[top = 1] = p;
for(int i = p; !Isroot(i); i = fa[i]) st[++top] = fa[i];
for(int i = top; i; --i) push_down(st[i]);
}
int find(int x) {return F[x] == x ? x : F[x] = find(F[x]);}
void Rotate(int p) {
int f = fa[p], g = fa[f], c = wh(p);
if(!Isroot(f)) ch[g][wh(f)] = p; fa[p] = g;
ch[f][c] = ch[p][c ^ 1]; if(ch[f][c]) fa[ch[f][c]] = f;
ch[p][c ^ 1] = f; fa[f] = p;
update(f);
}
void Splay(int p) {
push_up(p);
for(; !Isroot(p); Rotate(p))
if(!Isroot(fa[p])) Rotate(wh(fa[p]) == wh(p) ? fa[p] : p);
update(p);
}
void Access(int p) {
for(int pre = 0; p; pre = p, p = fa[p]) {
Splay(p);
isiz[p] += siz[rs] - siz[pre];
rs = pre;
update(p);
}
}
void makeroot(int p) {Access(p); Splay(p); rev[p] ^= 1;}
void Link(int p, int g) { makeroot(p); makeroot(g); fa[p] = g; isiz[g] += siz[p]; update(g); int fg = find(g); makeroot(rt[fg]); Access(p); Splay(rt[fg]); int S = siz[rt[fg]]; int t = ch[rt[fg]][1]; push_down(t); while(ch[t][0]) { t = ch[t][0]; push_down(t); } Access(t); if(((isiz[t] + 1) << 1) > S || ((isiz[t] + 1) << 1) == S && t < rt[fg]) { ans ^= rt[fg] ^ t; rt[fg] = t; } }
void dfs(int x, int f) {
ch[x][0] = ch[x][1] = fa[x] = rev[x] = 0;
isiz[x] = 0;
siz[x] = 1;
Link(x, f);
for(int i = pre[x]; i; i = e[i].next)
if(e[i].to != f)
dfs(e[i].to, x);
}
int main()
{
n = read();
for(int i = 1;i <= n; ++i) {
F[i] = rt[i] = i;
sz[i] = siz[i] = 1;
ans ^= i;
}
m = read();
while(m--) {
char opt = getchar();
while(opt < 'A' || opt > 'Z') opt = getchar();
if(opt == 'X') printf("%d\n", ans);
if(opt == 'A') {
int x = read(), y = read(), fx = find(x), fy = find(y);
if(sz[fx] > sz[fy]) swap(x, y), swap(fx, fy);
sz[fy] += sz[fx];
ans ^= rt[fx]; F[fx] = fy;
dfs(x, y);
adds(x, y);
}
if(opt == 'Q') printf("%d\n", rt[find(read())]);
}
return 0;
}
/*
10 1000000
A 1 2
A 2 3
A 1 4
Q 1
Q 2
Q 3
Q 4
A 2 5
Q 1
Q 2
Q 3
Q 4
Xor
A 2 3
A 2 4
A 2 5
Q 2
Xor
A 6 7
A 6 8
A 6 9
A 6 10
Q 6
Xor
Q 5
Q 2
Q 6
Xor
*/
相关文章推荐
- [BZOJ3510][启发式合并][LCT维护子树信息]首都
- BZOJ 3510: 首都 LCT维护子树信息 启发式合并
- 【BZOJ3510】首都 LCT维护子树信息+启发式合并
- 【bzoj3510】首都 LCT维护子树信息(+启发式合并)
- 【bzoj4530】[Bjoi2014]大融合 LCT维护子树信息
- [BZOJ3510]-首都-LCT维护重心
- 【BZOJ4530】[Bjoi2014]大融合 LCT维护子树信息
- [BZOJ4530][Bjoi2014][LCT维护子树信息]大融合
- 【bzoj 4530】大融合(LCT维护子树信息)
- 【LCT维护子树信息】BZOJ4530(Bjoi2014)[大融合]题解
- [BZOJ]4530 [BJOI2014] 大融合 LCT维护子树信息
- BZOJ 4530: [Bjoi2014]大融合 lct维护子树信息
- BZOJ4530 BJOI 2014 大融合 LCT维护子树信息
- BZOJ 4530 [Bjoi2014]大融合 LCT维护子树信息
- BZOJ 3779 重组病毒 LCT维护子树信息
- bzoj 4530: [Bjoi2014]大融合 lct维护子树信息
- [BZOJ4530]-大融合-LCT维护子树信息
- bzoj4530 [Bjoi2014]大融合 (LCT维护子树信息)
- BZOJ 2555 Substring(后缀自动机+LCT子树维护)
- BZOJ.3510.首都(LCT 启发式合并 树的重心)