Codeforces Round #551 (Div. 2) D Serval and Rooted Tree

https://codeforces.com/contest/1153/problem/D

题意:一棵树,每个点是取孩子的min或者max(输入给定),设叶子节点为k,用1-k去填,使根的值最小。

 

题解:

    我们先考虑min和max的意义:

       1.考虑倒数第二层的某个i,如果取最小,我们就需要对所有孩子结点进行赋值后的最小值相关,即取最小的那个,于是和孩子数量有关,而取最大值,只和其中一个有关,于是和孩子数量1有关,那么我们可以抽象设num[i]表示某个结点取最优方案时,要和几个叶子结点的取值有关。         2.倒数第三层及以上,若是最大值,类比改为num[i]=min{num[u]}u是i的孩子,和最小的那个相关即可;若是最小值,类比改为num[i]=\sum num[u],u是i的孩子。

    则最后根最优需要和num[1]个叶子有关,那么我们可以从k,k-1,k-num[1]+1去赋值,最后最优答案就是k-num[1]+1。

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#include<iostream>
#include<map>
#include<queue>
#define nn 300005
using namespace std;

int num[nn],is[nn],a,n,k;
vector<int>g[nn];


void dfs(int w){
    if (!g[w].size()){num[w]=1;k++;return;}
    if (is[w])num[w]=1000000000;else num[w]=0;
    
    for (int i=0;i<g[w].size();i++){int u=g[w][i];
        dfs(u);
        if (is[w])num[w]=min(num[w],num[u]);
        else num[w]+=num[u];
        }
    return;
    }
int main(){
    scanf("%d",&n);k=0;
    for (int i=1;i<=n;i++)scanf("%d",&is[i]);
    for (int i=2;i<=n;i++){
        scanf("%d",&a);
        g[a].push_back(i);
    }
    dfs(1);
    printf("%d\n",k-num[1]+1);
 //   for(;;);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/u014713777/article/details/89293595