题意:给出一颗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]); }