题目
给定一棵n(n<=3e5)的节点的有根树,
每个节点上有一个op值,
op=0代表该点的值取子树中的min值,
op=1代表该点的值取子树中的max值,
不妨设树有k个叶子,可以将1到k共k个不重复的值填到叶子中,
使得最后根节点的值最大,输出最大值
思路来源
https://www.cnblogs.com/FrankChen831X/p/10706038.html
好题,博主讲的真是清楚明白啊QAQ
题解
Treedp的题,多画图构造样例,这样才能找到规律
树形dp,dp[i]表示在合理分配时,i能取到的i的这棵子树的第x大值,显然,dp[叶子]=1,
①当i节点为max时,显然取叶子几个值中最大的那个,也就是dp[i]最小的那个
②当i节点为min时,不妨设有两个儿子,分别取第二大和第五大,
那么由于叶子结点不重复,i只能取到第一棵子树中第二和第二棵子树中第五的较小值,
即整棵子树中第七的值,推广得,取儿子dp[j]值之和
③有了dp[1]即根的rk之后,由于共k个叶子,取第rk大,即k-rk+1
代码
#include<bits/stdc++.h>
using namespace std;
const int N=3e5+10;
const int INF=0x3f3f3f3f;
//dp[i]:最好情况下 i能取到i的这棵子树的从大到小第x值
int n,num,op[N],dp[N],fa;
vector<int>E[N];
void dfs(int u,int fa)
{
if(!E[u].size())//叶
{
dp[u]=1;
num++;
return;
}
if(op[u]==1)dp[u]=INF;//mx
for(int v:E[u])
{
dfs(v,u);
if(op[u]==1)dp[u]=min(dp[u],dp[v]);//mx
else dp[u]+=dp[v];//mn
}
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;++i)
scanf("%d",&op[i]);
for(int i=2;i<=n;++i)
{
scanf("%d",&fa);
E[fa].push_back(i);
}
dfs(1,-1);
printf("%d\n",num+1-dp[1]);
return 0;
}