洛谷P2056 [ZJOI2007] 捉迷藏 题解 动态点分治/点分树

思路全部来自 OI WIKI:https://oi.wiki/graph/dynamic-tree-divide/

按照自己的码风写了一下。

示例程序:

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 5;

int n, Q, rt, fa[maxn], lit[maxn], lit_cnt;
bool vis[maxn];
vector<int> g[maxn];

struct LCA {

    int dep[maxn], fa[maxn][17];

    void dfs(int u, int p) {
        fa[u][0] = p;
        dep[u] = dep[p] + 1;
        for (auto v : g[u])
            if (v != p)
                dfs(v, u);
    }

    void build() {
        dfs(1, 0);
        for (int i = 1; i < 17; i++)
            for (int u = 1; u <= n; u++)
                fa[u][i] = fa[ fa[u][i-1] ][i-1];
    }

    int lca(int x, int y) {
        if (dep[x] < dep[y])
            swap(x, y);
        for (int i = 16; i >= 0; i--) {
            int p = fa[x][i];
            if (dep[p] >= dep[y]) x = p;
        }
        if (x == y)
            return x;
        for (int i = 16; i >= 0; i--)
            if (fa[x][i] != fa[y][i])
                x = fa[x][i], y = fa[y][i];
        return fa[x][0];
    }

    int dis(int x, int y) {
        return dep[x] + dep[y] - 2 * dep[lca(x, y)];
    }

} lca;

struct Heap {

    priority_queue<int> a, b;

    void push(int x) {
        a.push(x);
    }

    void del(int x) {
        b.push(x);
    }

    int top() {
        while (!b.empty() && a.top() == b.top()) a.pop(), b.pop();
        return a.top();
    }

    void pop() {
        while (!b.empty() && a.top() == b.top()) a.pop(), b.pop();
        a.pop();
    }

    int size() {
        return a.size() - b.size();
    }

    int top2() { // 最大的两个数之和
        int tmp = top(), res = tmp;
        pop();
        res += top();
        push(tmp);
        return res;
    }

} heap_fa[maxn], heap_me[maxn], ans;

int get_sz(int u, int p) {
    if (vis[u]) return 0;
    int sz = 1;
    for (auto v : g[u])
        if (v != p)
            sz += get_sz(v, u);
    return sz;
}

int get_wc(int u, int p, int tot, int &wc) {
    if (vis[u]) return 0;
    int sz = 1, mx = 0;
    for (auto v : g[u]) {
        if (v != p) {
            int tmp = get_wc(v, u, tot, wc);
            sz += tmp;
            mx = max(mx, tmp);
        }
    }
    mx = max(mx, tot - sz);
    if (mx <= tot / 2)
        wc = u;
    return sz;
}

void dfs_fa(int u, int p, int d, int x) {
    if (vis[u]) return;
    heap_fa[x].push(d);
    for (auto v : g[u])
        if (v != p)
            dfs_fa(v, u, d+1, x);
}

void pre(int u) {
    heap_me[u].push(0);
    vis[u] = true;
    for (auto v : g[u]) {
        if (vis[v]) continue;
        int x;
        get_wc(v, u, get_sz(v, u), x);
        dfs_fa(v, u, 1, x);
        heap_me[u].push(heap_fa[x].top());
        fa[x] = u;
        pre(x);
    }
    if (heap_me[u].size() >= 2)
        ans.push(heap_me[u].top2());
}

int main() {
    scanf("%d", &n);
    for (int i = 1, u, v; i < n; i++) {
        scanf("%d%d", &u, &v);
        g[u].push_back(v);
        g[v].push_back(u);
    }
    lca.build();
    get_wc(1, 0, n, rt);
    pre(rt);
    scanf("%d", &Q);
    while (Q--) {
        char op[2];
        scanf("%s", op);
        if (op[0] == 'G') {
            if (lit_cnt == n) puts("-1");
            else if (lit_cnt == n-1) puts("0");
            else printf("%d\n", ans.top());
        }
        else {
            int x;
            scanf("%d", &x);
            if (!lit[x]) {
                lit_cnt++;
                if (heap_me[x].size() >= 2)
                    ans.del(heap_me[x].top2());
                heap_me[x].del(0);
                if (heap_me[x].size() >= 2)
                    ans.push(heap_me[x].top2());
                for (int u = x; fa[u]; u = fa[u]) {
                    int p = fa[u];
                    if (heap_me[p].size() >= 2)
                        ans.del(heap_me[p].top2());
                    heap_me[p].del(heap_fa[u].top());
                    heap_fa[u].del(lca.dis(p, x));
                    if (heap_fa[u].size() >= 1)
                        heap_me[p].push(heap_fa[u].top());
                    if (heap_me[p].size() >= 2)
                        ans.push(heap_me[p].top2());
                }
            }
            else {
                lit_cnt--;
                if (heap_me[x].size() >= 2)
                    ans.del(heap_me[x].top2());
                heap_me[x].push(0);
                if (heap_me[x].size() >= 2)
                    ans.push(heap_me[x].top2());
                for (int u = x; fa[u]; u = fa[u]) {
                    int p = fa[u];
                    if (heap_me[p].size() >= 2)
                        ans.del(heap_me[p].top2());
                    if (heap_fa[u].size() >= 1)
                        heap_me[p].del(heap_fa[u].top());
                    heap_fa[u].push(lca.dis(p, x));
                    heap_me[p].push(heap_fa[u].top());
                    if (heap_me[p].size() >= 2)
                        ans.push(heap_me[p].top2());
                }
            }
            lit[x] ^= 1;
        }
    }
    return 0;
}
posted @ 2026-01-14 00:18  quanjun  阅读(5)  评论(0)    收藏  举报