思路:
看到树的题,第一想法往往就是先考虑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; }