树形DP.
用倍增处理出来每个点往上能延伸出去的最远路径,nlogn
对于每个节点,如果它能被后代使用过的点覆盖,就直接覆盖,这个点就不使用,否则就ans++,让传的Max改成dp[x]
#include <iostream> #include <cstdio> #include <cstring> using namespace std; typedef long long ll; const int N=100005; int n,a[N],fa[N][20],f[N],head[N],to[N<<1],nxt[N<<1],ecnt,ans,L; inline void add(int bg,int ed) { nxt[++ecnt]=head[bg];to[ecnt]=ed;head[bg]=ecnt; } ll S,v[N][20]; void dfs(int x) { for(int i=head[x];i;i=nxt[i]) if(to[i]!=fa[x][0]) fa[to[i]][0]=x,v[to[i]][0]=a[x],dfs(to[i]); } int Dfs(int x) { int Max=0; for(int i=head[x];i;i=nxt[i]) if(to[i]!=fa[x][0]) Max=max(Max,Dfs(to[i])); if(!Max) { ans++; return f[x]-1; } return Max-1; } int main() { cin>>n>>L>>S; for(int i=1;i<=n;i++) {scanf("%d",&a[i]);if(a[i]>S) return puts("-1"),0;} for(int i=1,x;i<n;i++) scanf("%d",&x),add(x,i+1),add(i+1,x); dfs(1); for(int i=1;(1<<i)<=L;i++) { for(int j=1;j<=n;j++) { fa[j][i]=fa[fa[j][i-1]][i-1]; v[j][i]=v[fa[j][i-1]][i-1]+v[j][i-1]; } } for(int i=1;i<=n;i++) { ll sum=a[i];int now=i;f[i]=1; for(int j=19;~j&&sum<=S;j--) { if(fa[now][j]&&sum+v[now][j]<=S&&f[i]+(1<<j)<=L) sum+=v[now][j],f[i]+=1<<j,now=fa[now][j]; } } Dfs(1); cout<<ans; return 0; }