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];

    }

}