[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;
}
posted @ 2021-06-06 23:43  AC-Evil  阅读(87)  评论(0编辑  收藏  举报