[WC2020]有根树
一道神题。做法瓶颈主要在于可能一次要维护大量的孩子的信息,为了避免,使用树剖将其维护量变成 \(\mathcal O(\log n)\)。使用链表优化细节。
复杂度 \(\mathcal O(q\log n)\)。
#include <bits/stdc++.h>
#define fi first
#define se second
#define pb push_back
#define lowbit(x) (x & (-x))
using std::vector; using std::set; using std::pair;
const int N = 5e5 + 5;
int n, Q, ans = 0, ptr = 0;
vector<int> G[N];
int dfn[N], idfn[N], fa[N], top[N], son[N], dep[N], siz[N], dfs_clock = 0, in[N];
void dfs1(int u, int f) {
siz[u] = 1; fa[u] = f; dep[u] = dep[f] + 1;
for (int v : G[u])
if (v != f) dfs1(v, u), siz[u] += siz[v], siz[v] > siz[son[u]] && (son[u] = v);
}
void dfs2(int u, int tp) {
top[u] = tp; idfn[dfn[u] = ++dfs_clock] = u;
if (son[u]) dfs2(son[u], tp);
for (int v : G[u])
if (v != fa[u] && v != son[u]) dfs2(v, v);
}
int bit[N];
void add(int i, int x) {
for (; i <= n; i += lowbit(i))
bit[i] += x;
}
int qry(int i) {
int ans = 0;
for (; i; i -= lowbit(i))
ans += bit[i];
return ans;
}
int qry(int l, int r) {
return qry(r) - qry(l - 1);
}
struct Data {
int head[N], la[N], ne[N];
void ins(int x, int v) {
int y = head[v];
if (y) ne[y] = x;
head[v] = x; la[x] = y; ne[x] = 0;
}
void del(int x, int v) {
int y = head[v];
if (x == y) head[v] = la[x];
if (la[x]) ne[la[x]] = ne[x];
if (ne[x]) la[ne[x]] = la[x];
}
int get(int v) { return head[v]; }
} A, B;
struct Chain {
set<int> X, Y;
int tX, tY, wX, wY;
Chain() { tX = tY = -1; }
void insX(int x) {
X.insert(dfn[x]);
if (~tX) A.del(tX, wX);
tX = idfn[*X.begin()]; wX = qry(dfn[tX], dfn[tX] + siz[tX] - 1);
A.ins(tX, wX);
}
void delX(int x) {
X.erase(dfn[x]);
A.del(tX, wX);
if (x == tX)
if (X.empty()) tX = -1;
else tX = idfn[*X.begin()];
if (~tX) A.ins(tX, wX = qry(dfn[tX], dfn[tX] + siz[tX] - 1));
}
void addX(int v) { if (~tX) A.del(tX, wX), A.ins(tX, wX += v); }
void insY(int x) {
Y.insert(-dfn[x]); in[x] = 1;
if (~tY) B.del(tY, wY);
tY = idfn[-*Y.begin()]; wY = qry(dfn[tY], dfn[tY] + siz[tY] - 1);
B.ins(tY, wY);
}
void delY(int x) {
Y.erase(-dfn[x]); in[x] = 0;
B.del(tY, wY);
if (x == tY)
if (Y.empty()) tY = -1;
else tY = idfn[-*Y.begin()];
if (~tY) B.ins(tY, wY = qry(dfn[tY], dfn[tY] + siz[tY] - 1));
}
void addY(int v) { if (~tY) B.del(tY, wY), B.ins(tY, wY += v); }
} lk[N];
void ins(int x) {
add(dfn[x], 1);
Chain *cur;
for (int u = x; u; u = fa[top[u]]) {
cur = &lk[top[u]];
if (~cur->tY && dfn[u] >= dfn[cur->tY])
cur->addY(1);
if (~cur->tX && dfn[u] >= dfn[cur->tX]) {
cur->addX(1);
if (cur->wX > ptr)
cur->insY(cur->tX), cur->delX(cur->tX), ans++;
}
}
cur = &lk[top[x]];
if (qry(dfn[x], dfn[x] + siz[x] - 1) > ptr)
cur->insY(x), ans++;
else cur->insX(x);
}
void del(int x) {
Chain *cur = &lk[top[x]];
if (in[x]) cur->delY(x), ans--;
else cur->delX(x);
add(dfn[x], -1);
for (int u = x; u; u = fa[top[u]]) {
cur = &lk[top[u]];
if (~cur->tX && dfn[u] >= dfn[cur->tX])
cur->addX(-1);
if (~cur->tY && dfn[u] >= dfn[cur->tY]) {
cur->addY(-1);
if (cur->wY < ptr)
cur->insX(cur->tY), cur->delY(cur->tY), ans--;
}
}
}
void XtoY() {
int x = A.get(ptr);
if (x) {
int u = top[x]; Chain *cur = &lk[u];
cur->delX(x), cur->insY(x);
ans++;
}
else ptr--;
}
void YtoX() {
int x = B.get(ptr);
if (x) {
int u = top[x]; Chain *cur = &lk[u];
cur->delY(x), cur->insX(x);
ans--;
}
else ptr++;
}
int main() {
scanf("%d", &n);
for (int i = 1; i < n; i++) {
int u, v; scanf("%d%d", &u, &v);
G[u].pb(v), G[v].pb(u);
}
dfs1(1, 0), dfs2(1, 1);
scanf("%d", &Q);
while (Q--) {
int op, x; scanf("%d%d", &op, &x);
if (op == 1) ins(x);
else del(x);
if (ptr != ans) ptr > ans ? XtoY() : YtoX();
printf("%d\n", ans);
}
return 0;
}