class Solution {
int N = 110, M = N * 2;
int[] he = new int[N], e = new int[M], ne = new int[M];
int[] vi, wi;
int n, c, idx;
// 定义 f[u][j] 为考虑以 u 为根的子树,背包容量不超过 j 的最大价值
int[][] f = new int[N][N];
// 链式向前星存图
void add(int a, int b) {
e[idx] = b;
ne[idx] = he[a];
he[a] = idx;
idx++;
}
void dfs(int u) {
// 节点 u 的价值和体积
int cw = wi[u], cv = vi[u];
// 要选任一节点,必须先选 u,同时也限制了至少需要 cv 的容量
for (int i = cv; i <= c; i++) f[u][i] += cw;
// 遍历节点 u 的所有子节点 x(分组背包遍历物品组)
for (int i = he[u]; i != -1; i = ne[i]) {
int x = e[i];
// 递归处理节点 x
dfs(x);
// 从大到小遍历背包容量(分组背包遍历容量)
for (int j = c; j >= 0; j--) {
// 遍历给节点 x 分配多少背包容量(分组背包遍历决策)
for (int k = 0; k <= j - cv; k++) {
f[u][j] = Math.max(f[u][j], f[u][j - k] + f[x][k]);
}
}
}
}
public int maxValue(int N, int C, int[] p, int[] v, int[] w) {
n = N; c = C;
vi = v; wi = w;
Arrays.fill(he, -1);
int root = -1;
for (int i = 0; i < n; i++) {
if (p[i] == -1) {
root = i;
} else {
add(p[i], i);
}
}
dfs(root);
return f[root][c];
}
}