Nowcoder13249.黑白树(树形DP)
一棵n个点的有根树,1号点为根,相邻的两个节点之间的距离为1。树上每个节点i对应一个值k[i]。每个点都有一个颜色,初始的时候所有点都是白色的。
你需要通过一系列操作使得最终每个点变成黑色。每次操作需要选择一个节点i,i必须是白色的,然后i到根的链上(包括节点i与根)所有与节点i距离小于k[i]的点都会变黑,已经是黑的点保持为黑。问最少使用几次操作能把整棵树变黑。
//先记一遍每个子树的最大向上高度
//然后对每个叶子节点染色
//遇到没染色的节点,去子树里找最大的高度,更新高度
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+100;
int n,k[maxn];
vector<int> g[maxn];
int dep[maxn];
int ans;
int h[maxn];//h_x表示x子树内可以往上走的最高高度
int f[maxn];//f_x表示x子树内当前往上走的最高高度
void dfs (int x,int pre) {
dep[x]=dep[pre]+1;
h[x]=dep[x]-k[x]+1;
for (int y:g[x]) {
if (y==pre) continue;
dfs(y,x);
h[x]=min(h[x],h[y]);
}
}
void dfs1 (int x,int pre) {
dep[x]=dep[pre]+1;
int Min=1e9;
for (int y:g[x]) {
if (y==pre) continue;
dfs1(y,x);
Min=min(Min,f[y]);
}
if (Min<=dep[x]) {
f[x]=Min;
}
else {
f[x]=h[x];
ans++;
}
}
int main () {
scanf("%d",&n);
for (int i=2;i<=n;i++) {
int x;
scanf("%d",&x);
g[x].push_back(i);
}
for (int i=1;i<=n;i++) scanf("%d",k+i),f[i]=1e9;
dfs(1,0);
dfs1(1,0);
printf("%d\n",ans);
}