思路
看到树的题,第一想法往往就是先考虑dfs
这题我们可以知道,叶子节点是一定要染色的,因为他染色是一个从叶子节点往父亲节点更新的过程。
那么我们应该考虑dfs应该要维护什么?
首先我们肯定是贪心的策略去做,就是我选了叶子节点开始染色,那么染过色的地方就尽量不要去选,这应该是最优策略。
但其实这样是有错误的
考虑这样一种情况 1<-2<-3<-4 这是其中一条链,假设k1=1,k2=1,k3=3,k4=2
按照上面的做法,我们从4开始染色,ok,3和4已经染色成功,然后继续2开始染色,ok,2染色成功,最后把根染色这样操作次数要3次。其实正确答案应该是2.
4开始染色,3和4覆盖,3染色,1和2覆盖,结束
所以我们不仅要维护染色的最远距离,同时还需要去更新掉父亲节点的染色距离,
比如在上述例子,k[2]=max(k[2],k[3]-1)=k[3]-1=2 这样就可以避免上述错误了。
dfs维护染色最远距离,并且把子节点的染色范围更新到父亲节点去取最大值即可。
如果到当前节点无法被子树中节点的染色覆盖,那么就要将当前节点染色。

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
vector<int> e[maxn];
int a[maxn];
int ans;
int dfs(int x,int fa){
    int sum=0;
    for(auto it:e[x]){
        sum=max(sum,dfs(it,x));
    }
    if(sum==0) {
        ans++;
        return a[x]-1;
    }
    a[fa]=max(a[fa],a[x]-1);
    return sum-1;
}
int main(){
    int n;cin>>n;
    for(int i=2;i<=n;i++){
        int x;cin>>x;
        e[x].push_back(i);
    }
    for(int i=1;i<=n;i++) cin>>a[i];
    dfs(1,0);
    cout<<ans<<endl;
    return 0;
}