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]=,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;
}