【树DP】CF#551(div2)D

传送门

题意是每个节点有一个属性,取子树的最大或最小值。只有叶子节点有初始值,可以分别是1 – n(叶子节点个数)里面的任意一个值。问根节点最大值是多少。

很巧妙的思路。

对于每一个节点,在他及其子树中,相对大小都是确定了的。

CF例图

比如在上图里。
节点{4}取最小,在{8, 9}里是第二大。
节点{2}取最大,在{8, 9, 5}里是第一大。
设f[i]表示i个节点的相对大小(第几大)。
对于每个节点,都需要尽量的大。所以f[i]需要尽量小。对于取\min的点,一定是子树的rank之和。而去\max的点,一定是子树的rank1.

最后拿总数减去根节点的rank就是根节点的取值

#include<bits/stdc++.h>
using namespace std;
const int maxn = 3e5 + 233;
vector<int> G[maxn];
int c[maxn], f[maxn], cnt;
void dfs(int x)
{
    if(c[x]) f[x] = 1e9;
    for(int i = 0; i < G[x].size(); i++)
    {
        int y = G[x][i];
        dfs(y);
        if(c[x]) f[x] = min(f[x], f[y]);
        else f[x] += f[y];
    }
    if(!G[x].size()) f[x] = 1, cnt++;
}
int main()
{
    int n ; cin >> n;
    for(int i = 1; i <= n; i++)
    {
        scanf("%d", &c[i]);
    }
    for(int i = 2; i <= n; i++)
    {
        int k; scanf("%d", &k);
        G[k].push_back(i);
    }
    dfs(1);
    cout << cnt - f[1] + 1;
}

发表评论

邮箱地址不会被公开。 必填项已用*标注