题目简述:树版[k取方格数]
众所周知,桂木桂马是攻略之神,开启攻略之神模式后,他可以同时攻略k部游戏。
今天他得到了一款新游戏《XX半岛》,这款游戏有n个场景(scene),某些场景可以通过不同的选择支到达其他场景。所有场景和选择支构成树状结构:开始游戏时在根节点(共通线),叶子节点为结局。每个场景有一个价值,现在桂马开启攻略之神模式,同时攻略k次该游戏,问他观赏到的场景的价值和最大是多少(同一场景观看多次是不能重复得到价值的)
“为什么你还没玩就知道每个场景的价值呢?”
“我已经看到结局了。”
Input
第一行两个正整数n,k
第二行n个正整数,表示每个场景的价值
以下n-1行,每行2个整数a,b,表示a场景有个选择支通向b场景(即a是b的父亲)
保证场景1为根节点 对于100%的数据,n<=200000,1<=场景价值<=2^31-1
Output
输出一个整数表示答案
Sample Input
5 2
4 3 2 1 1
1 2
1 5
2 3
2 4
Sol:找出每个点的最长链放入堆中(注意权值是在点上面的),每次找出最长链,并从堆中删除
#include <cstdio> #include <algorithm> #include <queue> using namespace std; typedef long long ll; const int N = 200005; struct edges { int next, to; edges() {} edges(int _n, int _t) : next(_n), to(_t) {} } e[N]; struct data { ll first; int w; data() {} data(ll _f, int _w) : first(_f), w(_w) {} inline bool operator < (const data &b) const { return first < b.first; } }; int n, k; int first[N], tot; int v[N]; bool vis[N]; ll mx[N], ans; priority_queue <data> h; inline int read() { int x = 0, sgn = 1; char ch = getchar(); while (ch < '0' || '9' < ch) { if (ch == '-') sgn = -1; ch = getchar(); } while ('0' <= ch && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); } return sgn * x; } inline void add_edge(int x, int y) { e[++tot] = edges(first[x], y); first[x] = tot; } void dfs(int p) { int x, y; for (x = first[p]; x; x = e[x].next) dfs(y = e[x].to), mx[p] = max(mx[p], mx[y]); mx[p] += v[p]; h.push(data(mx[p], p)); //找出每个点的最长链,放到堆中 } void del(int p) { int x, y; vis[p] = 1;//将其打上删除标记,在堆中并没有删除之 for (x = first[p]; x; x = e[x].next) if (mx[y = e[x].to] == mx[p] - v[p]) { del(y); break; } } int main() { int i, p, x, y; n = read(), k = read(); for (i = 1; i <= n; ++i) v[i] = read(); for (i = 1; i < n; ++i) { x = read(), y = read(); add_edge(x, y); } dfs(1); for (; k && !h.empty(); --k) { while (vis[h.top().w] && !h.empty()) //如果这个点删除过了,并且堆并不为空时 h.pop(); if (h.empty()) break; ans += mx[p = h.top().w]; del(p); } printf("%lld\n", ans); return 0; }