W15 CF739B

题意:给出一颗n(1e5)个节点的树,树上边权(1e9),每个节点有一个a值,输出对于每个节点v有多少个子节点u满足dist(u,v)<=au

sol

开始题意读错了,看成av,肝不出来

做法就是每个点v对于和它距离小于av的祖先产生贡献,这个可以用一个栈保存路径,加个二分。开始还想祖先dfs序不连续怎么用数据结构维护,一想就询问一次,树上差分就可以了啊

#include<iostream>
#include<cstdio>
#include<cstring>
#define LL long long
#define N (200100)
using namespace std;
LL dep[N];
int n,A[N],h[N],m1,St[N],tp,fa[N],B[N];
struct edge{
    int next,to;
    LL val;
    void Add(int Next,int To,LL v){
        next=Next; to=To; val=v;
    }
}q[3*N];
void Addedge(int x,int y,LL v){
    q[++m1].Add(h[x],y,v); h[x]=m1;
}
void Dfs1(int x){
    int i,y;
    for (i=h[x];i;i=q[i].next){
        y=q[i].to;
        dep[y]=dep[x]+q[i].val;
        
        int l=1,r=tp,ans=0;
        while (l<=r){
            int mid=(l+r)>>1;
            if (dep[y]-dep[St[mid]]<=A[y]){
                ans=mid; r=mid-1;
            }
            else l=mid+1;
        }
        if (ans)
            B[fa[y]]++,B[fa[St[ans]]]--;
        St[++tp]=y;
        Dfs1(y);
        tp--;
    }
}
void Dfs2(int x){
    int i,y;
    for (i=h[x];i;i=q[i].next){
        y=q[i].to;
        Dfs2(y);
        B[x]+=B[y];
    }
}
int main(){
    scanf("%d",&n);
    int i;
    for (i=1;i<=n;i++) scanf("%d",&A[i]);
    for (i=2;i<=n;i++){
        LL val;
        scanf("%d %I64d",&fa[i],&val);
        Addedge(fa[i],i,val); 
    }
    St[1]=tp=1;
    Dfs1(1); Dfs2(1);
    for (i=1;i<=n;i++) printf("%d ",B[i]);
}

猜你喜欢

转载自www.cnblogs.com/Pedestrian6/p/9200864.html