[Codeforces682C]Alyona and the Tree

传送门
题意
在一棵树上存在这样一个节点 u ,满足 u 存在 v 的子树中,若 d i s ( u , v ) >= a [ u ] 那么 u 点是 s a d 的233你只能从叶子节点开始删除点,问你最少删除多少个点,可以使得这个树里面没有不开心的点
题解
wow发现这道题好6啊!(来自蒟蒻的感慨….
来好好分析一下这道题 如果我们找到了一个点是 s a d 的 那么我们就要把他整棵子树给删掉
那么我们的问题就转换成了找 s a d 的点即它子树的大小了 继续思考下去 发现 s a d 点并不好求
因为边权有可能是负的 但点权肯定是大于等于1的
那么我们就转换成求不需要删除的点
我们一路 d f s 下去的时候
就记录下每个点到根的距离(注意啦注意啦( d f s 的时候距离要和 0 取个 m a x

#include<bits/stdc++.h>
#define LL long long
using namespace std;
const int N=1e5+1;
struct data{
    int next,to,w;
}a[N<<1];
int head[N];
LL v[N];
int ans=0,cnt=0;

void add(int x,int y,int w){
    a[++cnt].to=x,a[cnt].next=head[y],a[cnt].w=w,head[y]=cnt;
    a[++cnt].to=y,a[cnt].next=head[x],a[cnt].w=w,head[x]=cnt;
}

int dfs(int u,int fa,LL dis){
    if(dis>v[u]) return 0;
    int res=1;
    for(int i=head[u];i!=-1;i=a[i].next){
        if(a[i].to!=fa){
            res+=dfs(a[i].to,u,max(dis+a[i].w,0LL));     //
        }
    }
    return res;
}

int main(){
    int n,son,w;scanf("%d",&n);
    memset(head,-1,sizeof(head));
    for(int i=1;i<=n;++i) scanf("%lld",&v[i]);
    for(int i=1;i<n;++i){
        scanf("%d%d",&son,&w);
        add(i+1,son,w);
    }
    ans=dfs(1,0,0);
    printf("%d",n-ans);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/LLL_Amazing/article/details/82226442