• [WC2020]有根树


    一道神题。做法瓶颈主要在于可能一次要维护大量的孩子的信息,为了避免,使用树剖将其维护量变成 (mathcal O(log n))。使用链表优化细节。

    复杂度 (mathcal O(qlog 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
    ", ans);
    	}
    	return 0;
    }
    
  • 相关阅读:
    CCF-CSP题解 201509-4 高速公路
    CCF-CSP题解 201403-4 无线网络
    CCF-CSP题解 201512-4 送货
    2019年9月10日
    53. 最大子序和
    54. 螺旋矩阵
    59. 螺旋矩阵 II
    61. 旋转链表
    62. 不同路径
    70. 爬楼梯
  • 原文地址:https://www.cnblogs.com/ac-evil/p/14856909.html
Copyright © 2020-2023  润新知