n个节点以1为根的一棵树,每个非叶子节点都有一个操作max或min(0表示min,1表示max),表示这个节点中的值应该分别等于其子节点中所有值的最大值或最小值。假设树上有k个叶节点,你可以将每个叶节点填上[1,k]的数字,且每个数字只使用一次,求根节点的最大值

题解:
树形dp

可以看出来是个树形dp结构,f[i]代表i节点下的子树,需要使用多少个节点,即表示节点i的权值在这个子树的所有叶节点中最小排名,那1节点的答案最大就是 k - f[1] + 1

转移:

当前节点如果权值是1,说明要取最大值,那我们就要选一个最小的排名来更新父亲节点,所以对他下面的节点求个min

如果是0,说明要取最小值那就保证当前节点排名最靠后,所以就是对他下面所有节点求sum,就是下面所有节点的最小排名

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e6 + 5;
int a[maxn], head[maxn], tot;
int dp[maxn];
struct Edge {
    int u, v, next;
}edge[maxn];

void init() {
    memset(head, -1, sizeof(head)); tot;
}

void add(int u, int v) {
    edge[++tot].u = u; edge[tot].v = v; 
    edge[tot].next = head[u]; head[u] = tot;
}
int k;
const int inf = 1e9;
void dfs(int u,  int fa) {
    if (head[u] == -1 || edge[head[u]].v == fa) {
        k++; dp[u] = 1; return ;
    }
    if (a[u]) dp[u] = inf;
    else dp[u] = 0;
    for (int i = head[u]; i != -1; i = edge[i].next) {
        int to = edge[i].v;
        if (to == fa) continue;
        dfs(to, u);
        if (a[u]) dp[u] = min(dp[u], dp[to]);
        else dp[u] += dp[to];
    }
}

int main() {
    int n, x;
    init();
    cin >> n;
    for (int i = 1; i <= n; i++) {
        cin >> a[i];
    }
    for (int i = 2; i <= n; i++) {
        cin >> x;
        add(x, i); add(i, x);
    }
    dfs(1, 0);
    cout << k - dp[1] + 1 << endl;
    return 0;
}