bzoj 1095: [ZJOI2007]Hide 捉迷藏
Description
捉迷藏 Jiajia和Wind是一对恩爱的夫妻,并且他们有很多孩子。某天,Jiajia、Wind和孩子们决定在家里玩捉迷藏游戏。他们的家很大且构造很奇特,由N个屋子和N-1条双向走廊组成,这N-1条走廊的分布使得任意两个屋子都互相可达。游戏是这样进行的,孩子们负责躲藏,Jiajia负责找,而Wind负责操纵这N个屋子的灯。在起初的时候,所有的灯都没有被打开。每一次,孩子们只会躲藏在没有开灯的房间中,但是为了增加刺激性,孩子们会要求打开某个房间的电灯或者关闭某个房间的电灯。为了评估某一次游戏的复杂性,Jiajia希望知道可能的最远的两个孩子的距离(即最远的两个关灯房间的距离)。 我们将以如下形式定义每一种操作: C(hange) i 改变第i个房间的照明状态,若原来打开,则关闭;若原来关闭,则打开。 G(ame) 开始一次游戏,查询最远的两个关灯房间的距离。
Input
第一行包含一个整数N,表示房间的个数,房间将被编号为1,2,3…N的整数。接下来N-1行每行两个整数a, b,
表示房间a与房间b之间有一条走廊相连。接下来一行包含一个整数Q,表示操作次数。接着Q行,每行一个操作,如
上文所示。
Output
对于每一个操作Game,输出一个非负整数到hide.out,表示最远的两个关灯房间的距离。若只有一个房间是关
着灯的,输出0;若所有房间的灯都开着,输出-1。
Sample Input
8
1 2
2 3
3 4
3 5
3 6
6 7
6 8
7
G
C 1
G
C 2
G
C 1
G
Sample Output
4
3
3
4
HINT
对于(100\%)的数据,(N le 100000, M le 500000)。
上次罗老师讲了这道题,今天才写这道题。
此题我们首先要进行树分治。
先通过树分治的重心建一棵树,每个节点维护两个堆,一个维护子树到节点的距离,另一个维护其子树的第一个堆的堆顶。
我们再利用一个全局堆维护答案。
#include <queue>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 100013;
class heap {
protected:
priority_queue < int > A, B;
public:
void push(const int &x) {
A.push(x);
}
void erase(const int &x) {
B.push(x);
}
void pop() {
while (!B.empty() && !(A.top() ^ B.top()))
A.pop(), B.pop();
A.pop();
}
int top() {
while (!B.empty() && !(A.top() ^ B.top()))
A.pop(), B.pop();
return A.empty() ? -0x3f3f3f3f : A.top();
}
int size() const {
return A.size() - B.size();
}
bool empty() const {
return !(A.size() ^ B.size());
}
int tps() {
if (size() < 2) return -0x3f3f3f3f;
int t1, t2;
while (!B.empty() && !(A.top() ^ B.top()))
A.pop(), B.pop();
t1 = A.top(); A.pop();
while (!B.empty() && !(A.top() ^ B.top()))
A.pop(), B.pop();
t2 = A.top(); A.push(t1);
return t1 + t2;
}
}GlobleHeap, FirstHeap[N], SecondHeap[N];
struct edge {
int t;
edge *n;
} me[N << 1 | 1], *ce = me, *g[N];
inline void adde(const int &a, const int &b) {
ce->t = b, ce->n = g[a], g[a] = ce++;
}
int deep[N], fa[20][N], dis[20][N], size[N], f[N], totsize, rt, tot_off;
bool vis[N], on[N];
inline void cmax(int &a, const int &b) {
if (a < b) a = b;
}
void grt(int u, int father) {
int v;
size[u] = 1, f[u] = 0;
for (edge *it = g[u]; it; it = it->n) {
v = it->t;
if (vis[v] || (v == father)) continue;
grt(v, u);
size[u] += size[v];
cmax(f[u], size[v]);
}
cmax(f[u], totsize - size[u]);
if (f[u] < f[rt]) rt = u;
}
void dfs(int u, const int &anc, int father, int dep) {
int v;
for (edge *it = g[u]; it; it = it->n) {
v = it->t;
if (vis[v] || (v == father)) continue;
fa[++deep[v]][v] = anc;
dis[deep[v]][v] = dep;
dfs(v, anc, u, dep + 1);
}
}
void build(int u) {
int v, all = totsize;
vis[u] = true;
dfs(u, u, 0, 1);
for (edge *it = g[u]; it; it = it->n) {
if (vis[v = it->t]) continue;
if (size[u] < size[v])
size[v] = all - size[u];
totsize = size[v];
rt = 0;
grt(v, u);
build(rt);
}
}
inline void turn_off(const int &u) {
static int t, i, pre;
SecondHeap[u].push(0);
if (SecondHeap[u].size() == 2)
GlobleHeap.push(SecondHeap[u].top());
for (i = deep[u]; i > 1; --i)
if (FirstHeap[fa[i][u]].empty()) {
FirstHeap[fa[i][u]].push(dis[i - 1][u]);
pre = SecondHeap[fa[i - 1][u]].tps();
SecondHeap[fa[i - 1][u]].push(dis[i - 1][u]);
if (pre > 0) {
if (pre ^ (t = SecondHeap[fa[i - 1][u]].tps())) {
GlobleHeap.erase(pre);
GlobleHeap.push(t);
}
} else if ((t = SecondHeap[fa[i - 1][u]].tps()) > 0)
GlobleHeap.push(t);
} else {
t = FirstHeap[fa[i][u]].top();
FirstHeap[fa[i][u]].push(dis[i - 1][u]);
if (t < dis[i - 1][u]) {
pre = SecondHeap[fa[i - 1][u]].tps();
SecondHeap[fa[i - 1][u]].erase(t);
SecondHeap[fa[i - 1][u]].push(dis[i - 1][u]);
if (pre > 0 && (pre ^ (t = SecondHeap[fa[i - 1][u]].tps()))) {
GlobleHeap.erase(pre);
GlobleHeap.push(t);
}
}
}
}
inline void turn_on(const int &u) {
SecondHeap[u].erase(0);
if (SecondHeap[u].size() == 1)
GlobleHeap.erase(SecondHeap[u].top());
for (int t, pre, i = deep[u]; i > 1; --i) {
FirstHeap[fa[i][u]].erase(dis[i - 1][u]);
if (FirstHeap[fa[i][u]].top() < dis[i - 1][u]) {
pre = SecondHeap[fa[i - 1][u]].tps();
SecondHeap[fa[i - 1][u]].erase(dis[i - 1][u]);
if (!FirstHeap[fa[i][u]].empty())
SecondHeap[fa[i - 1][u]].push(FirstHeap[fa[i][u]].top());
if (pre > 0 && (pre ^ (t = SecondHeap[fa[i - 1][u]].tps()))) {
GlobleHeap.erase(pre);
if (SecondHeap[fa[i - 1][u]].size() > 1)
GlobleHeap.push(t);
}
}
}
}
inline void Switch(const int &u) {
if (on[u]) turn_off(u);
else turn_on(u);
on[u] ^= 1;
if (on[u]) --tot_off;
else ++tot_off;
}
int main() {
//freopen("1095.in", "r", stdin);
int n, m, u, v;
char ops[4];
scanf("%d", &n);
for (m = 1; m < n; ++m) {
scanf("%d%d", &u, &v);
adde(u, v), adde(v, u);
}
f[0] = 0x3f3f3f3f;
totsize = tot_off = n;
grt(1, 0);
build(rt);
for (m = 1; m <= n; ++m)
fa[++deep[m]][m] = m, turn_off(m);
scanf("%d", &m);
while (m--) {
scanf("%s", ops);
if (*ops == 'G') {
if (!tot_off)puts("-1");
else printf("%d
", max(GlobleHeap.top(), 0));
} else {
scanf("%d", &u);
Switch(u);
}
}
return 0;
}