其他分享
首页 > 其他分享> > P2495 [SDOI2011]消耗战

P2495 [SDOI2011]消耗战

作者:互联网

【题意】

给定一个有边权的树,m次询问,每次给定k个关键点,求所有关键点互不相连的最小代价

 

【分析】

CF613D Kingdom and its Cities十分相似,建立好虚树后,设计树形dp

f[i]表示i子树内的关键点都互相断开的答案,那么对于每个节点u:

如果u是关键点,可以考虑断开u的所有存在关键点的儿子

如果u不是关键点,则有两种选择,可以断开u->son的点,也可以断开son子树内的关键点,即f[u]=f[u]+min(e[i].v,f[son])

注意清零的方式即可

【代码】

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define inf 123456789000000000
#define mod 1000000007
const int maxn=3e5+5; 
int read()
{
    int x = 0, f = 1; char c = getchar();
    while(c < '0' || c > '9') { if(c == '-') f = -1; c = getchar();}
    while(c >= '0' && c <= '9') x = x * 10 + c - 48, c = getchar();
    return x * f;
}
struct edge
{
    int v, w, next;
}e[maxn << 1];
int n, m, head[maxn], cnt, is[maxn], mi[maxn], dfn[maxn], col, t;
int size[maxn], fa[maxn], top[maxn], son[maxn], dep[maxn], s[maxn];
vector<int>v[maxn];
void add(int u, int v, int w)
{
    e[++ cnt] = (edge){v, w, head[u]};
    head[u] = cnt;
}
bool cmp(int a, int b){return dfn[a] < dfn[b];}
void dfs1(int u, int fr)
{
    size[u] = 1, fa[u] = fr, dep[u] = dep[fr] + 1;
    for(int i = head[u]; i; i = e[i].next)
    {
        int v = e[i].v;
        if(v == fr) continue;
        mi[v] = min(mi[u], e[i].w);
        dfs1(v, u), size[u] += size[v];
        if(size[son[u]] < size[v]) son[u] = v;
    }
}
void dfs2(int u, int fr)
{
    top[u] = fr, dfn[u] = ++ col;
    if(!son[u]) return;
    dfs2(son[u], fr);
    for(int i = head[u]; i; i = e[i].next)
    {
        int v = e[i].v;
        if(v != fa[u] && v != son[u]) dfs2(v, v);
    }
}
int lca(int a, int b)
{
    while(top[a] != top[b]) dep[top[a]] > dep[top[b]] ? a = fa[top[a]] : b = fa[top[b]];
    return dep[a] < dep[b] ? a : b;
}
void push(int x)
{
    if(t == 1) {s[++ t] = x;return;}
    int l = lca(x, s[t]);
    if(l == s[t]) return;
    while(t > 1 && dfn[s[t - 1]] >= dfn[l]) v[s[t - 1]].push_back(s[t]), --t;
    if(s[t] != l) v[l].push_back(s[t]), s[t] = l;
    s[++ t] = x;
}
int dp(int u)
{
    if(v[u].size() == 0) return mi[u];
    int temp = 0;
    for(int i = 0; i < v[u].size(); ++ i) temp += dp(v[u][i]);
    v[u].clear();
    return min(mi[u], temp);
}
signed main()
{
    n = read();
    for(int i = 1; i < n; ++ i)
    {
        int u = read(), v = read(), w = read();
        add(u, v, w), add(v, u, w);
    }
    mi[1] = inf, dfs1(1, 0), dfs2(1, 1);
    int T = read();
    while(T --)
    {
        m = read();
        for(int i = 1; i <= m; ++ i) is[i] = read();
        sort(is + 1, is + m + 1, cmp);
        s[t = 1] = 1;
        for(int i = 1; i <= m; ++ i) push(is[i]);
        while(t > 0) v[s[t - 1]].push_back(s[t]), --t;
        printf("%lld\n", dp(1));
    }
    return 0;
}

 

标签:return,int,top,son,SDOI2011,read,消耗战,P2495,size
来源: https://www.cnblogs.com/andylnx/p/14792281.html