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 ≤100000, M ≤500000。

Solution

不会括号序列做法 留个记号 以后研究。。。

动态树分治?

用数据结构维护树分治的树上信息的修改和查询。

这道题每个节点开两个堆

h1维护子树中的点权

h2维护孩子们h1.top()

每次修改暴力计算修改的点到当前节点距离更新h1,h2即可。

可合并堆?用删除标记堆实现~

Code

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
#include <queue>
#include <cstdio>
#include <algorithm>
using namespace std;
const int maxn = 100005;
bool vis[maxn], col[maxn];
pair<int, int> res;
struct edge_t { int to, next; } edge[maxn << 1];
int n, m, N, siz[maxn], h[maxn], cnte, fa[maxn], dep[maxn], clo, id[maxn], mi[maxn << 1][20], cnt_black, L2[maxn << 1];
inline int getint() {
	int r = 0; bool z = true; char c = getchar();
	for (; c < '0' || c > '9'; c = getchar()) if (c == '-') z = false;
	for (; '0' <= c && c <= '9'; c = getchar()) r = r * 10 - '0' + c;
	if (z) return r;
	return -r;
}
inline void ins(int x, int y) {
	edge[++cnte].to = y;
	edge[cnte].next = h[x];
	h[x] = cnte;
}
struct ly {
	priority_queue<int> a, b;
	inline void nn() { while (b.size() && a.top() == b.top()) a.pop(), b.pop(); }
	inline int siz() { return a.size() - b.size(); }
	inline int fir() { nn(); return a.top(); }
	inline void del(int x) { b.push(x); nn(); }
	inline void add(int x) { nn(); a.push(x); }
	inline int sec() {
		int mag = fir(); a.pop();
		int hsk = fir(); add(mag);
		return mag + hsk;
	}
} h1[maxn], h2[maxn], ans;
void fetch(int now, int father, int deep, ly& dst) {
	siz[now] = 1; dst.add(deep);
	for (int i = h[now]; i; i = edge[i].next) {
		if (vis[edge[i].to] || father == edge[i].to) continue;
		fetch(edge[i].to, now, deep + 1, dst);
		siz[now] += siz[edge[i].to];
	}
}
void dfs(int now, int father, int deep) {
	dep[now] = mi[++clo][0] = deep; id[now] = clo;
	for (int i = h[now]; i; i = edge[i].next) {
		if (edge[i].to == father) continue;
		dfs(edge[i].to, now, deep + 1);
		mi[++clo][0] = deep;
	}
}
inline void add(ly& x) { if (x.siz() > 1) ans.add(x.sec()); }
inline void del(ly& x) { if (x.siz() > 1) ans.del(x.sec()); }
inline int lyn(int a, int b) {
	a = id[a]; b = id[b];
	if (a > b) swap(a, b);
	int t = L2[b-a+1];
	return min(mi[a][t], mi[b-(1<<t)+1][t]);
}
inline int calc(int x, int y) { return dep[x] + dep[y] - (lyn(x, y) << 1); }
inline void modify(int x) {
	bool sta = !col[x];
	if (sta) ++cnt_black; else --cnt_black;
	del(h2[x]);
	if (sta) h2[x].add(0); else h2[x].del(0);
	add(h2[x]);
	for (int i = x; fa[i]; i = fa[i]) {
		del(h2[fa[i]]);
		if (h1[i].siz() > 0) h2[fa[i]].del(h1[i].fir());
		if (sta) h1[i].add(calc(x, fa[i])); else h1[i].del(calc(x, fa[i]));
		if (h1[i].siz() > 0) h2[fa[i]].add(h1[i].fir());
		add(h2[fa[i]]);
	}
	col[x] = sta;
}
void find_root(int now, int father) {
	int tmp = 1; siz[now] = 1;
	for (int i = h[now]; i; i = edge[i].next) {
		if (vis[edge[i].to] || father == edge[i].to) continue;
		find_root(edge[i].to, now);
		siz[now] += siz[edge[i].to];
		tmp = max(tmp, siz[edge[i].to]);
	}
	tmp = max(tmp, N - siz[now]);
	res = min(res, make_pair(tmp, now));
}
int get_root(int now, int father, int size) {
	res = make_pair(2147483647, 0);
	N = size;
	find_root(now, father);
	return res.second;
}
void solve(int now) {
	int i, j;
	h2[now].add(0);
	vis[now] = true;
	for (i = h[now]; i; i = edge[i].next) {
		if (vis[edge[i].to]) continue;
		ly tmp;
		fetch(edge[i].to, now, 1, tmp);
		j = get_root(edge[i].to, now, siz[edge[i].to]);
		h1[j] = tmp; fa[j] = now;
		h2[now].add(tmp.fir());
		solve(j);
	}
	add(h2[now]);
}
int main() {
	n = cnt_black = getint(); int x, y;
	for (int i = 1; i < n; ++i) {
		x = getint(); y = getint();
		ins(x, y); ins(y, x);
		col[i] = true;
	}
	col[n] = true; dfs(1, 0, 0);
	for (int i = 2; i <= clo; ++i) L2[i] = L2[i>>1]+1;
	for (int j = 1; j <= 19; ++j)
		for (int i = 1; i + (1<<j) - 1 <= clo; ++i)
			mi[i][j] = min(mi[i][j-1], mi[i+(1<<(j-1))][j-1]);
	solve(get_root(1, 0, n));
	char str[3];
	int Q = getint();
	while (Q--) {
		scanf("%s", str);
		if (str[0] == 'C') modify(getint());
		else {
			if (cnt_black < 2) printf("%d\n", cnt_black - 1);
			else printf("%d\n", ans.fir());
		} 
	}
}