题意是取k个点,每次累加从根到这个点的权值的和,最多只能加一次,问最大能得到多少。
用sum[i]表示i到叶子节点的最大的路径上的和,son[i]表示和最大的路径上的i的孩子,father[i]表示和最大的路径上的i的父亲。
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <iostream>
using namespace std;
#define maxn 111111
struct node {
int from, to, next;
}edge[maxn*2];
int head[maxn], cnt;
long long sum[maxn], a[maxn];
int n, k, t, father[maxn], son[maxn];
long long ans[maxn];int ans_cnt;
void add_edge (int from, int to, int i) {
node &e = edge[i];
e.from = from, e.to = to, e.next = head[from], head[from] = i;
}
void dfs (int u, int fa) {
for (int i = head[u]; i != -1; i = edge[i].next) {
int v = edge[i].to;
if (v == fa)
continue;
dfs (v, u);
if (sum[v] > sum[u]) {
son[u] = v;
sum[u] = sum[v];
}
}
father[son[u]] = u;
sum[u] += a[u];
return ;
}
int main () {
//freopen ("in", "r", stdin);
scanf ("%d", &t);
int kase = 0;
while (t--) {
scanf ("%d%d", &n, &k);
int u, v;
for (int i = 1; i <= n; i++) {
scanf ("%lld", &a[i]);
}
cnt = 0;
memset (head, -1, sizeof (head));
for (int i = 1; i < n; i++) {
scanf ("%d%d", &u, &v);
add_edge (u, v, cnt++);
add_edge (v, u, cnt++);
}
memset (sum, 0, sizeof sum);
memset (father, -1, sizeof father);
memset (son, -1, sizeof son);
dfs (1, 0);
ans_cnt = 0;
for (int i = 1; i <= n; i++) {
if (father[i] == -1) {
ans[ans_cnt++] = sum[i];
}
}
sort (ans, ans+ans_cnt);
long long gg = 0;
for (int i = 1, j = ans_cnt-1; i <= min (ans_cnt, k); i++, j--)
gg += ans[j];
printf ("Case #%d: %lld\n", ++kase, gg);
}
return 0;
}