感受
我真菜,居然做不出来
什么时候我可以变得强起来!


思路
看完题解后,恍然大悟。
对于一个一定不能由子树覆盖的点,那么这个点一定要染色。
那么染色一定是染这个点w吗?不是,其实可以染子树中的任意一点,只需要保证染完之后,假设染的是u,那么从u到w后的向上延伸距离最大(k[u] - (dep[u] - dep[w]).
题解在处理这个子问题时比我的想法简单不少,可以一直更新每一个节点的最大延伸距离,然后从而达到这个效果。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 10;
struct edge{
    int v, nex;
}e[maxn * 2];
int head[maxn], cnt, n;
int dp[maxn], k[maxn];///dp[i]表示i节点往上还可以最多走几步(走到的位置为必须染色时刻)
///k[i]表示以i为当前根的子树所有节点到达i后还可以往上走步数的最大值
void add_edge(int u, int v){
    cnt++;
    e[cnt] = (edge){v, head[u]};
    head[u] = cnt;
}
int ans;
void dfs(int u, int f){
    int v;
    for(int i = head[u]; i > 0; i = e[i].nex){
        v = e[i].v;
        if(v == f) continue;
        dfs(v, u);
        dp[u] = max(dp[u], dp[v] - 1);
        k[u] = max(k[u], k[v] - 1);
    }
    if(!dp[u]){
        ans++;
        dp[u] = k[u];
    }

}
int main(){
    scanf("%d", &n);
    int fa;
    for(int i = 2; i <= n; i++){
        scanf("%d", &fa);
        add_edge(i, fa); add_edge(fa, i);
    }
    for(int i = 1; i <= n; i++){scanf("%d", &k[i]);}
    dfs(1, 0);
    printf("%d\n", ans);
    return 0;
}