题面:
题解:
因为是向上染色,所以叶子节点肯定要选。接下来就是两种情况:
1.节点 i 能不能被子树中的点染色,那么这个点肯定会被选。
2.节点 i 能被子树中的某个点 j 染色,那么就出现了一个问题,i 这个点要不要选,因为我们可以先染 i 点再染 j 点,怎么去处理呢?
我们可以将儿子节点附在父亲节点上,然后去更新父亲节点的最远距离:k[fa]=max(k[fa],k[son]-1)。 这样做可以将那些还没用到的点的剩余价值放在祖先节点,如果那些选择的点无法染到节点 i ,那么此时就可以用那些没被选的点去染。那么怎么去看被选的点能否染到点 i 呢?可以设dp[i] 表示 i 的子树中选的点能延伸到的最远距离。那么就是dp[u]=max(dp[u],dp[v]-1)。
代码:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<stack>
#include<set>
#define iss ios::sync_with_stdio(false)
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
typedef pair<int,int>pii;
const int MAXN=1e5+5;
const int mod=1e9+7;
const int inf=0x3f3f3f3f;
struct node
{
int to;
int next;
}e[MAXN<<1];
int head[MAXN],k[MAXN];
int cnt=0;
int fa[MAXN];
int ans=0;
int dp[MAXN];
void add(int u,int v)
{
e[cnt].to=v;
e[cnt].next=head[u];
head[u]=cnt++;
}
void dfs(int u,int f)
{
for(int i=head[u];i!=-1;i=e[i].next)
{
int v=e[i].to;
if(v==f) continue;
dfs(v,u);
dp[u]=max(dp[u],dp[v]-1);
}
if(!dp[u])
{
ans++;
dp[u]=k[u];
}
else
{
k[fa[u]]=max(k[fa[u]],k[u]-1);
}
}
int main()
{
int n;
memset(head,-1,sizeof head);
cin>>n;
fa[1]=0;
for(int i=2;i<=n;i++)
{
int x;
cin>>x;
add(x,i);
add(i,x);
fa[i]=x;
}
for(int i=1;i<=n;i++)
{
cin>>k[i];
}
dfs(1,0);
printf("%d\n",ans);
}