BZOJ3252 攻略
Problem
给定一棵包含
每个节点有一个权值
现在想要最大化收益,请给出最大的收益值。
Input
第一行两个正整数
第二行 n 个正整数,表示每个节点的权值。
接下来
数据保证节点
Output
输出一个整数表示最大的收益。
Sample
Input 1
5 2
4 3 2 1 1
1 2
1 5
2 3
2 4
Output 1
10
Solution
考虑将原树类似树链剖分那样切开,但这里不是根据子树大小来断开,而是比较权值大小。(注意要先将链上节点的权值求和再比较)
然后对于每一条链,权值求和塞进堆中,取出最大的前
证明一下正确性:
如果一个节点与父亲断开被记为轻链,那这个父亲节点的重儿子上链的权值和一定是大于该点链上权值和的,选择时优先重儿子一定是正确的。
因此,假如一个轻儿子被选择,那其父亲节点的重儿子那条链一定被选择过了,该点到根节点的路径上的节点权值也是被统计过了的。
代码:
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <queue>
using namespace std;
const int kmax = 2e5 + 3;
struct E {
int p, y;
} e[kmax << 1];
int n, k;
long long w[kmax], res;
int h[kmax], ec;
int son[kmax];
priority_queue<long long> q;
void Addedge(int x, int y) {
e[++ec] = {h[x], y};
h[x] = ec;
}
void Dfs(int x, int fa) {
for (int i = h[x]; i; i = e[i].p) {
int y = e[i].y;
if (y == fa) continue;
Dfs(y, x);
if (w[y] > w[son[x]]) {
son[x] = y;
}
}
w[x] += w[son[x]];
}
void Dfss(int x, int fa, int tp) {
if (x == tp) q.push(w[x]);
if (son[x]) Dfss(son[x], x, tp);
for (int i = h[x]; i; i = e[i].p) {
int y = e[i].y;
if (y == fa || y == son[x]) continue;
Dfss(y, x, y);
}
}
int main() {
freopen("game.in", "r", stdin);
freopen("game.out", "w", stdout);
scanf("%d%d", &n, &k);
for (int i = 1; i <= n; i++) {
scanf("%lld", &w[i]);
}
for (int i = 1, x, y; i < n; i++) {
scanf("%d%d", &x, &y);
Addedge(x, y);
}
Dfs(1, 0);
Dfss(1, 0, 1);
for (int i = 1; i <= k && !q.empty(); i++, q.pop()) {
res += q.top();
//cout << q.top() << '\n';
}
printf("%lld\n", res);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】