虚树

  • 如果关键节点比较少,可以用虚树,把非关键节点的链化成边或删去

  • 例题 : luogu P2495 [SDOI2011]消耗战

#include <cstdio>
#include <cstring>
#include <algorithm>

typedef long long ll;
const int N = 2.5e5 + 5;

int read(int x = 0, int f = 1, char c = getchar()) {
    for (; c < '0' || c > '9'; c = getchar())
        if (c == '-') f = -1;
    for (; c >='0' && c <='9'; c = getchar())
        x = x * 10 + c - '0';
    return x * f;
}

struct Edge {
    int n, t, d;
}e[N*2];
int h[N], edc;

void Add(int x, int y, int z = 0) {
    e[++edc] = (Edge) {h[x], y, z}; h[x] = edc;
}

int n, fa[N], dep[N], son[N], sz[N], tp[N], dfn[N], dfc, a[N], stk[N], top;
bool v[N];
ll d[N];

void Dfs(int x) {
    sz[x] = 1; dep[x] = dep[fa[x]] + 1;
    for (int i = h[x], y; i; i = e[i].n) {
        if ((y = e[i].t) == fa[x]) continue;
        d[y] = std::min(d[x], (ll)e[i].d);
        fa[y] = x; Dfs(y); sz[x] += sz[y];
        if (!son[x] || sz[son[x]] < sz[y]) son[x] = y;
    }
}

void Dfs(int x, int top) {
    tp[x] = top; dfn[x] = ++dfc;
    if (son[x]) Dfs(son[x], top);
    for (int i = h[x], y; i; i = e[i].n)
        if ((y = e[i].t) != fa[x] && y != son[x]) Dfs(y, y);
}

bool Cmp(const int &a, const int &b) {
    return dfn[a] < dfn[b];
}

int Lca(int x, int y) {
    while (tp[x] != tp[y])
        dep[tp[x]] > dep[tp[y]] ? x = fa[tp[x]] : y = fa[tp[y]];
    return dep[x] < dep[y] ? x : y;
}

ll Cal(int x) {
    ll ans = 0;
    for (int i = h[x], y; i; i = e[i].n)
        ans += Cal(e[i].t);
    if (v[x]) ans = d[x];
    else ans = std::min(d[x], ans);
    v[x] = h[x] = 0;
    return ans;
}

int main() {
    n = read();
    for (int i = 1; i < n; ++i) {
        int x = read(), y = read(), z = read();
        Add(x, y, z); Add(y, x, z);
    }
    d[1] = 1e18; Dfs(1); Dfs(1, 1);
    memset(h + 1, 0, n * 4); edc = 0;
    for (int m = read(); m; --m) {
        int k = read();
        for (int i = 1; i <= k; ++i) a[i] = read();
        std::sort(a + 1, a + k + 1, Cmp);
        stk[top = 1] = 1;
        for (int i = 1; i <= k; ++i) {
            int lca = Lca(stk[top], a[i]); v[a[i]] = 1;
            if (lca == stk[top]) { stk[++top] = a[i]; continue; }
            for (; top > 1 && dep[stk[top]] > dep[lca]; --top) 
                Add(dep[stk[top-1]] > dep[lca] ? stk[top-1] : lca, stk[top]);
            if (dep[lca] > dep[stk[top]]) stk[++top] = lca;
            stk[++top] = a[i];
        }
        while (top > 1) Add(stk[top-1], stk[top]), top--;
        printf("%lld
", Cal(1)); edc = 0;
    }
    return 0;
}
原文地址:https://www.cnblogs.com/shawk/p/14267268.html