HDU 5242 Game 贪心

题意:

给出一颗有根树,每个顶点上有一个权值\(w_i\)。求前\(k\)大条链的权值之和。

分析:

首先\(dfs\)预处理一遍\(d(u)\),表示从顶点\(u\)往下走能得到的最大权值和,顺便还要记录这是从\(u\)的哪个儿子转移上来的。
最开始我们取树中最大的一条链,取完以后树会分裂成若干不相交的子树。然后再从这些子树中取一条能得到最大权值的链,然后继续分裂。
每次取走一条链后,新出现的子树的根节点是链上所有点的没被取走的儿子节点。
这个过程用一个优先队列维护即可。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <map>
#define MP make_pair
using namespace std;

typedef long long LL;
typedef pair<LL, int> PII;
const int maxn = 100000 + 10;

struct Edge
{
    int v, nxt;
    Edge() {}
    Edge(int v, int nxt):v(v), nxt(nxt) {}
};

int root, ecnt, head[maxn];
Edge edges[maxn];

int n, k;
LL w[maxn];
int indeg[maxn];

void init() {
    ecnt = 0;
    memset(head, 0, sizeof(head));
    memset(indeg, 0, sizeof(indeg));
}

void AddEdge(int u, int v) {
    edges[++ecnt] = Edge(v, head[u]);
    head[u] = ecnt;
}

LL d[maxn];
int Mson[maxn];

void dfs(int u) {
    d[u] = w[u];
    LL Max = -1;
    for(int i = head[u]; i; i = edges[i].nxt) {
        int v = edges[i].v;
        dfs(v);
        if(d[v] > Max) { Max = d[v]; Mson[u] = v; }
    }
    if(Max >= 0) d[u] += Max;
}

priority_queue<PII> Q;

int main()
{
    int T; scanf("%d", &T);
    for(int kase = 1; kase <= T; kase++) {
        init();
        scanf("%d%d", &n, &k);
        for(int i = 1; i <= n; i++) scanf("%lld", w + i);
        for(int i = 1; i < n; i++) {
            int u, v; scanf("%d%d", &u, &v);
            AddEdge(u, v);
            indeg[v]++;
        }

        for(int i = 1; i <= n; i++) if(!indeg[i]) { root = i; break; }

        memset(Mson, 0, sizeof(Mson));
        dfs(root);
        while(!Q.empty()) Q.pop();
        Q.push(MP(d[root], root));
        LL ans = 0;
        for(int i = 0; i < k && !Q.empty(); i++) {
            PII x = Q.top(); Q.pop();
            ans += x.first;
            int u = x.second;
            for(; u; u = Mson[u]) {
                for(int j = head[u]; j; j = edges[j].nxt) {
                    int v = edges[j].v;
                    if(v != Mson[u]) Q.push(MP(d[v], v));
                }
            }
        }

        printf("Case #%d: %lld\n", kase, ans);
    }

    return 0;
}
posted @ 2015-11-05 23:07  AOQNRMGYXLMV  阅读(232)  评论(0编辑  收藏  举报