传送门:
题意
给
你
一
棵
树
,
你
可
以
去
掉
m
个
点
(
m
∈
[
0
,
n
]
)
,
然
后
计
算
剩
余
结
点
的
贡
献
。
给你一棵树,你可以去掉m个点(m\in [0,n]),然后计算剩余结点的贡献。
给你一棵树,你可以去掉m个点(m∈[0,n]),然后计算剩余结点的贡献。
每
个
结
点
的
贡
献
为
它
本
身
的
价
值
加
上
它
所
有
直
接
相
连
儿
子
的
价
值
。
每个结点的贡献为它本身的价值加上它所有直接相连儿子的价值。
每个结点的贡献为它本身的价值加上它所有直接相连儿子的价值。
当
然
你
需
要
合
理
安
排
删
去
的
i
个
结
点
使
贡
献
最
小
化
。
输
出
每
个
i
对
应
的
贡
献
值
。
当然你需要合理安排删去的i个结点使贡献最小化。输出每个i对应的贡献值。
当然你需要合理安排删去的i个结点使贡献最小化。输出每个i对应的贡献值。
思路
有 树 、 节 点 、 贡 献 , 得 出 树 形 d p 。 有树、节点、贡献,得出树形dp。 有树、节点、贡献,得出树形dp。
设
f
[
i
]
[
j
]
表
示
以
i
为
根
节
点
的
子
树
中
留
下
j
个
节
点
的
最
小
贡
献
。
设f[i][j]表示以i为根节点的子树中留下j个节点的最小贡献。
设f[i][j]表示以i为根节点的子树中留下j个节点的最小贡献。
题
意
表
示
,
必
须
杀
掉
父
节
点
才
能
杀
掉
子
节
点
,
所
以
父
节
点
是
否
存
活
也
很
关
键
。
即
:
题意表示,必须杀掉父节点才能杀掉子节点,所以父节点是否存活也很关键。即:
题意表示,必须杀掉父节点才能杀掉子节点,所以父节点是否存活也很关键。即:
f
[
0
]
[
i
]
[
j
]
表
示
删
掉
i
后
留
下
j
个
节
点
的
最
小
贡
献
。
f[0][i][j]表示删掉i后留下j个节点的最小贡献。
f[0][i][j]表示删掉i后留下j个节点的最小贡献。
f
[
1
]
[
i
]
[
j
]
表
示
保
留
i
后
留
下
j
−
1
个
节
点
的
最
小
贡
献
。
f[1][i][j]表示保留i后留下j-1个节点的最小贡献。
f[1][i][j]表示保留i后留下j−1个节点的最小贡献。
状
态
转
移
都
是
从
子
节
点
转
移
到
父
节
点
:
状态转移都是从子节点转移到父节点:
状态转移都是从子节点转移到父节点:
f
[
0
]
[
u
]
[
j
+
k
]
=
m
i
n
(
f
[
0
]
[
u
]
[
j
+
k
]
,
f
[
0
]
[
u
]
[
j
]
+
m
i
n
(
f
[
0
]
[
v
]
[
k
]
,
f
[
1
]
[
v
]
[
k
]
)
)
f[0][u][j+k]=min(f[0][u][j+k],f[0][u][j]+min(f[0][v][k],f[1][v][k]))
f[0][u][j+k]=min(f[0][u][j+k],f[0][u][j]+min(f[0][v][k],f[1][v][k]))
f
[
1
]
[
u
]
[
j
+
k
]
=
m
i
n
(
f
[
1
]
[
u
]
[
j
+
k
]
,
f
[
1
]
[
u
]
[
j
]
+
m
i
n
(
f
[
0
]
[
v
]
[
k
]
,
f
[
1
]
[
v
]
[
k
]
+
v
a
l
[
v
]
)
)
f[1][u][j+k]=min(f[1][u][j+k],f[1][u][j]+min(f[0][v][k],f[1][v][k]+val[v]))
f[1][u][j+k]=min(f[1][u][j+k],f[1][u][j]+min(f[0][v][k],f[1][v][k]+val[v]))
第 二 个 为 什 么 要 加 上 v a l [ v ] , 因 为 题 意 说 对 于 一 个 节 点 的 贡 献 , 是 自 己 加 上 所 有 儿 子 的 权 值 。 第二个为什么要加上val[v],因为题意说对于一个节点的贡献,是自己加上所有儿子的权值。 第二个为什么要加上val[v],因为题意说对于一个节点的贡献,是自己加上所有儿子的权值。
上 面 的 状 态 转 移 直 接 背 包 即 可 。 上面的状态转移直接背包即可。 上面的状态转移直接背包即可。
Code
#include "bits/stdc++.h"
using namespace std;
typedef long long ll;
const int N = 5e3 + 10;
ll val[N];
int siz[N];
ll f[2][N][N];
vector<int> g[N];
void dfs(int u) {
siz[u] = 1;
f[1][u][1] = val[u];
f[0][u][0] = 0;
for(auto v : g[u]) {
dfs(v);
for(int j = siz[u];j >= 0; j--) {
for(int k = siz[v];k >= 0; k--) {
f[0][u][j + k] = min(f[0][u][j + k], f[0][u][j] + min(f[0][v][k], f[1][v][k]));
f[1][u][j + k] = min(f[1][u][j + k], f[1][u][j] + min(f[0][v][k], f[1][v][k] + val[v]));
}
}
siz[u] += siz[v];
}
}
void solve() {
int _; cin >> _;
while(_--) {
int n; cin >> n;
for(int i = 0;i <= n; i++) {
g[i].clear();
for(int j = 0;j <= n; j++) {
f[0][i][j] = f[1][i][j] = 1e18;
}
}
for(int i = 2;i <= n; i++) {
int u; cin >> u;
g[u].eb(i);
}
for(int i = 1;i <= n; i++) cin >> val[i];
dfs(1);
for(int i = n;i >= 0; i--) {
cout << min(f[0][1][i], f[1][1][i]) << " \n"[i == 0];
}
}
}
signed main() {
solve();
}