社区讨论
【悬关】选课(树上背包)加强版求调
学术版参与者 1已保存回复 0
讨论操作
快速查看讨论及其快照的属性,并进行相关操作。
- 当前回复
- 0 条
- 当前快照
- 1 份
- 快照标识符
- @mhj01ce7
- 此快照首次捕获于
- 2025/11/03 18:30 4 个月前
- 此快照最后确认于
- 2025/11/03 18:30 4 个月前
因为 太大所以
CPPf 必须压成一维,弱数据的二维写法放在了注释里。加强版死活 50 分,不太清楚是原本的二维写法就有问题(原题数据太弱了,可能测不出来)还是压成一维的代码有问题。#include <iostream>
#include <vector>
using namespace std;
const int N = 100000, M = 100000, NM = 1e8;
int n, m, s[N + 5], siz[N + 5], f[NM + N + M + 5];
vector<int> e[N + 5];
void calc(int u)
{
for (auto v : e[u])
{
calc(v);
// 目前 siz[u] 记录已合并的子树的大小的和
for (int i = min(m, siz[u] + siz[v]); i >= 1; i--) // 把目前所有子树都选上也只有 siz[u] + siz[v] 个
for (int j = max(i - siz[u], 0); j <= min(i, siz[v]); j++) // 子树 v 中至少选 i - siz[u] 个,不然达不到选 i 个;全选是 siz[v] 个,不可能更多
// f[u][i] = max(f[u][i], f[u][i - j] + f[v][j]);
f[u * (m + 1) + i] = max(f[u * (m + 1) + i], f[u * (m + 1) + i - j] + f[v * (m + 1) + j]);
siz[u] += siz[v];
}
siz[u]++; // 加上 u 本身
if (u != 0) // 子树合并的时候没有考虑选 u 本身,如果 u 不是虚拟根结点 0 那么就必须选 u 本身
for (int i = siz[u]; i >= 1; i--)
// f[u][i] = f[u][i - 1] + s[u];
f[u * (m + 1) + i] = f[u * (m + 1) + i - 1] + s[u];
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
cin >> n >> m;
for (int i = 1; i <= n; i++)
{
int k;
cin >> k >> s[i];
e[k].push_back(i);
}
calc(0);
cout << f[m] << "\n";
return 0;
}
回复
共 0 条回复,欢迎继续交流。
正在加载回复...