您的位置:首页 > 运维架构

bzoj3510首都 LCT维护子树信息+启发式合并

2017-10-19 09:09 405 查看

3510: 首都

Time Limit: 10 Sec  Memory Limit: 256 MB
Submit: 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 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。 

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
*/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: