P2056 [ZJOI2007]捉迷藏

给定一颗树

  • 改变第 $i$个房间的照明状态,若原来打开,则关闭;若原来关闭,则打开。
  • 查询最远的两个关灯房间的距离。

如果没有修改直径,只需要根据对一颗子树维护,每个儿子的链长的最大值,然后整体的$最大+次大值$。

可以用点分树优化,修改某个点的子树的信息

  • 显然他所有与他有关的子树的结点,那么对于子树$u$,他会少了$dis(fa[u],x)$这一个权值,近而影响到了$fa[u]$这颗大子树的最大值与最小值之和,然后又影响到了整体维护的最大值。
  • 第一个影响,删除或者添加堆中的元素即可。
  • 第二个影响,先删除$u$,对$fa[u]$的影响,然后再重新$push$进大子树。
  • 第三个影响与第二个大同小异
  • 注意细节和边界!!
  • 其实可用$Set$代替,据说常数过大
代码
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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define pii pair<int, int>
#define mk make_pair
const int N = 2e5 + 10;
const int mod = 1e9 + 7;
int read()
{
int x = 0, f = 1;
char c = getchar();
while (c < '0' || c > '9')
{
if (c == '-')
f = -1;
c = getchar();
}
while (c >= '0' && c <= '9')
x = (x << 1) + (x << 3) + c - '0', c = getchar();
return x * f;
}
struct Pq
{
priority_queue<int> q1, q2;
void push(int x) { q1.push(x); }
void del(int x) { q2.push(x); }
int size() { return q1.size() - q2.size(); }
void work()
{
while (!q1.empty() && !q2.empty() && q1.top() == q2.top())
q1.pop(), q2.pop();
}
int top()
{
work();
return q1.top();
}
int stop()
{
work();
int x1 = q1.top();
q1.pop();
work();
int res = q1.top();
q1.push(x1);
return res;
}

} A, B[N], C[N];
inline void pusha(int u)
{
if (B[u].size() >= 2)
A.push(B[u].top() + B[u].stop());
}
inline void dela(int u)
{
if (B[u].size() >= 2)
A.del(B[u].top() + B[u].stop());
}
vector<int> g[N];
int st[N][20], dfn[N], dep[N], tot, lg2[N];
void lcadfs(int x, int fa, int d)
{
st[++tot][0] = x;
dep[x] = d;
dfn[x] = tot;
for (int to : g[x])
{
if (to == fa)
continue;
lcadfs(to, x, d + 1);
st[++tot][0] = x;
}
}
int lower(int u, int v)
{
return (dep[u] < dep[v]) ? u : v;
}

void Lca_init()
{

lcadfs(1, 0, 1);

for (int i = 2; i <= tot; i++)
lg2[i] = lg2[i >> 1] + 1;
for (int l = 1; (1 << l) <= tot; l++)
{
for (int i = 1; i + (1 << l) - 1 <= tot; i++)
st[i][l] = lower(st[i][l - 1], st[i + (1 << (l - 1))][l - 1]);
}
}

int lca(int u, int v)
{
u = dfn[u];
v = dfn[v];
if (u > v)
swap(u, v);
int i = lg2[v - u + 1], w = (1 << i);
return lower(st[u][i], st[v - w + 1][i]);
}
int dis(int u, int v)
{
return dep[u] + dep[v] - 2 * dep[lca(u, v)];
}

int siz[N], f[N], vis[N];
int rt;
int father[N];
void GetRoot(int x, int fa, int gcnt)
{
siz[x] = 1;
f[x] = 0;
for (int to : g[x])
{
if (to == fa || vis[to])
continue;
GetRoot(to, x, gcnt);
siz[x] += siz[to];
f[x] = max(f[x], siz[to]);
}
f[x] = max(f[x], gcnt - siz[x]);
if (f[x] < f[rt])
rt = x;
}
void work(int x, int fa, int v)
{
C[v].push(dis(father[v], x));
for (int to : g[x])
{
if (vis[to] || to == fa)
continue;
work(to, x, v);
}
}
void calc(int x)
{
work(x, 0, x);
B[father[x]].push(C[x].top());
}
void solve(int x, int gcnt)
{

B[x].push(0);
vis[x] = 1;
calc(x);
for (int to : g[x])
{
if (vis[to])
continue;

int k = (siz[to] < siz[x]) ? siz[to] : (gcnt - siz[x]);
rt = 0;

GetRoot(to, x, k);
father[rt] = x;

solve(rt, k);
}
pusha(x);
}
void modify1(int x)
{
dela(x), B[x].del(0), pusha(x);
int now = x, last = 0;
while (father[now])
{
dela(father[now]);
B[father[now]].del(C[now].top());
C[now].del(dis(father[now], x));
if (C[now].size())
B[father[now]].push(C[now].top());
pusha(father[now]);
now = father[now];
}
}
void modify2(int x)
{
dela(x), B[x].push(0), pusha(x);
int now = x, last = 0;
while (father[now])
{
dela(father[now]);
if (C[now].size())
B[father[now]].del(C[now].top());
C[now].push(dis(father[now], x));
B[father[now]].push(C[now].top());
pusha(father[now]);
now = father[now];
}
}
int turn[N], num;
int main()
{
int n = read();
for (int i = 1; i < n; i++)
{
int u = read(), v = read();
g[u].push_back(v);
g[v].push_back(u);
}
Lca_init();
rt = 0,
f[0] = 1e9;
//cout << 2333 << endl;
GetRoot(1, 0, n);
solve(rt, n);

int m = read();
for (int i = 1; i <= m; i++)
{
char ch[2];
scanf("%s", ch);
if (ch[0] == 'G')
{
if (num == n - 1)
printf("0\n");
else if (num == n)
printf("-1\n");
else
printf("%d\n", A.top());
}
else
{
int x = read();
if (turn[x] == 0)
modify1(x), num++, turn[x] = 1;
else
modify2(x), num--, turn[x] = 0;
}
}
}