E. Split the Tree 題解(樹上倍增)
阿新 • • 發佈:2021-10-27
題目連結
題目思路
就是用樹上倍增首先預處理每個點向上最遠跳幾步
然後再dfs選取最優的子兒子即可
程式碼
不擺爛了,寫題#include<bits/stdc++.h> #define fi first #define se second #define debug cout<<"I AM HERE"<<endl; using namespace std; typedef long long ll; const int maxn=1e5+5,inf=0x3f3f3f3f,mod=998244353; const double eps=1e-7; int n,l; ll s; int fa[maxn][25],a[maxn]; ll v[maxn][25]; int f[maxn]; vector<int> g[maxn]; int pr=0; int dfs(int x){ int ma=0; for(auto nxt:g[x]){ ma=max(ma,dfs(nxt)); } if(ma==0){ pr++; return f[x]-1; } return ma-1; } signed main(){ bool flag=1; scanf("%d%d%lld",&n,&l,&s); for(int i=1;i<=n;i++){ scanf("%d",&a[i]); if(a[i]>s) flag=0; } if(!flag){ printf("-1\n"); return 0; } for(int i=2;i<=n;i++){ scanf("%d",&fa[i][0]); g[fa[i][0]].push_back(i); v[i][0]=a[fa[i][0]]; } for(int j=1;j<=20;j++){ for(int i=1;i<=n;i++){ fa[i][j]=fa[fa[i][j-1]][j-1]; v[i][j]=v[i][j-1]+v[fa[i][j-1]][j-1]; } } for(int i=2;i<=n;i++){ int sz=l-1,now=i; ll sum=s-a[i]; f[i]=1; for(int j=20;j>=0;j--){ if(!fa[now][j]) continue; if((1<<j)>sz) continue; if(v[now][j]>sum) continue; f[i]+=(1<<j); sum-=v[now][j]; sz-=(1<<j); now=fa[now][j]; } } dfs(1); printf("%d\n",pr); return 0; }