题目链接
题目大意
现在有一棵树,节点和边都有权值,我们规定一个点是sad点它要满足:dis(v,u)>a[u],其中u是v的子树节点中的其中一个,dis是(u,v)之间的最短路径,a[u]是u节点的点权。如果要这个树种没有sad节点,要删除多少个点
解题思路
很显然,如果要删除一个点,这个点的子树都要删掉。因为u是v的子树节点中的其中一个,那么我们只需要去保存当前节点和祖先节点之间路径的最大值,当不满足的时候,就不需要继续往下搜索了,ans保存不是sad节点有多少个,n-ans就是最后的答案了
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
const int N=1e5+5;
int a[N],f[N],tot,ans;
struct node
{
int v,nex;
long long w;
};
node e[3*N];
void add(int u,int v,long long w)
{
e[tot].v=v;
e[tot].w=w;
e[tot].nex=f[u];
f[u]=tot++;
}
void dfs(int u,int fa,long long dis)
{
if(a[u]<dis)
return ;
ans++;
for(int i=f[u];i!=-1;i=e[i].nex)
{
int v=e[i].v;
if(v!=fa)
dfs(v,u,max(e[i].w,dis+e[i].w));
}
}
int main()
{
int n;
while(~scanf("%d",&n))
{
ans=0;
memset(f,-1,sizeof(f));
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
int x;
long long y;
for(int i=2;i<=n;i++)
{
scanf("%d %lld",&x,&y);
add(i,x,y);
add(x,i,y);
}
dfs(1,-1,(long long)0);
printf("%d\n",n-ans);
}
return 0;
}