题意:n个结点带权树,边可以为负,n<=1e5,要求对每个v:满足若u为v的子孙,dist(u,v)<=a[u],op:每次可以删除leaf,问最小操作次数
令dp[u]为以u开头(往祖先走)的最大子串和,(或者递归时保存最小的dist[1,v],dist[u,v]=dist[1,u]-dist[1,v]]),若dp[u]>a[u] 则u是肯定要删除滴.
op每次只能删除leaf,当u变为leaf 删除的为u的子树大小,从上往下删除保证不重复删
dp[u]=max(dp[u],dp[v]+w)
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> ii;
const int N=2e5+20;
const ll inf=2e15;
int n,a[N],vis[N],sz[N];
ll dp[N];
int ans;
vector<ii> e[N];
void dfs(int u)
{
for(int i=0;i<e[u].size();i++)
{
int v=e[u][i].first,w=e[u][i].second;
dp[v]=max(dp[v],w+dp[u]);//祖先的dp值要先确定
dfs(v);
sz[u]+=sz[v];
}
}
void dfs_del(int u)
{
if(dp[u]>a[u])
{
ans+=sz[u];
return;
}
for(int i=0;i<e[u].size();i++)
{
int v=e[u][i].first;
dfs_del(v);
}
}
int main()
{
while(cin>>n)
{
ans=0;
memset(vis,0,sizeof(vis));
for(int i=1;i<=n;i++)
scanf("%d",&a[i]),dp[i]=0,e[i].clear(),sz[i]=1;
int u,w;
for(int i=2;i<=n;i++)
{
scanf("%d%d",&u,&w);
e[u].push_back(ii(i,w));
}
dfs(1);//calc
dfs_del(1);
cout<<ans<<endl;
}
return 0;
}