题目链接
给出一棵 n n n 个点的有根树,点和边都带权 ,该树以 1 1 1 号节点为跟
设 d i s t ( x , y ) dist(x,y) dist(x,y) 为 x x x 到 y y y 的路径上的边权和
如果 u u u 在 v v v 的子树中,且 d i s t ( u , v ) ≤ a u dist(u,v) \le a_u dist(u,v)≤au ( a a a 为点权),那么我们称顶点 v v v 控制顶点 u u u ( v ≠ u ) (v \neq u) (v=u)。
对于每个节点 1 ≤ x ≤ n 1 \le x \le n 1≤x≤n,你需要求出它控制了的节点个数
设 path ( i , j ) \operatorname{path}(i,j) path(i,j) 为 i i i 到 j j j 的路径上的点的集合
考虑计算每个节点做出的贡献,也就是看它被哪些节点控制
因为一个点只能控制自己子树中的点,所以点 x x x 只可能对 path ( f [ x ] , 1 ) \operatorname{path}(f[x],1) path(f[x],1) 上的点做出贡献。又因为该路径上的点到 x x x 的距离是单调递增的,所以一定存在点 y y y,满足 x x x 对 path ( f [ x ] , y ) \operatorname{path}(f[x],y) path(f[x],y) 上的点做出了贡献。当然,它也可能不对任何点做出贡献
我们考虑 dfs,在递归的时候维护出每个点 x x x 到根的路径上的点。因为他们离点 x x x 的距离满足单调性,所以我们可以用二分找到满足要求的最远的点 y y y,并将 path ( f [ x ] , y ) \operatorname{path}(f[x],y) path(f[x],y) 上的点加上一点贡献(可以用树剖或树上差分实现)。
#include // 这里写的是树剖
#include
#include
#include
using namespace std;
const long long Maxn=200000+20,inf=(1ll<<60);
const long long Maxm=Maxn<<1;
long long id[Maxn],son[Maxn],top[Maxn];
long long f[Maxn][23],dis[Maxn];
long long s[Maxn],d[Maxn];
long long sum[Maxm<<1],add[Maxm<<1];
long long head[Maxn],nxt[Maxm];
long long to[Maxm],len[Maxm];
long long c[Maxn],a[Maxn],tot;
long long n,idcnt,edgecnt=1;
inline void addedge(long long x,long long y,long long val)
{
++edgecnt;
nxt[edgecnt]=head[x];
to[edgecnt]=y;
len[edgecnt]=val;
head[x]=edgecnt;
}
inline long long read()
{
int s=0,w=1;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0' && ch<='9')s=(s<<3)+(s<<1)+(ch^48),ch=getchar();
return s*w;
}
inline void push_up(long long k)
{
sum[k]=sum[k<<1]+sum[k<<1|1];
}
inline void upd(long long k,long long l,long long r,long long v)
{
add[k]+=v,sum[k]+=(r-l+1)*v;
}
inline void push_down(long long k,long long l,long long r)
{
if(!add[k])return;
int mid=(l+r)>>1;
upd(k<<1,l,mid,add[k]);
upd(k<<1|1,mid+1,r,add[k]);
add[k]=0;
}
void modify(long long k,long long l,long long r,long long x,long long y,long long v)
{
if(x<=l && r<=y)return upd(k,l,r,v);
push_down(k,l,r);
long long mid=(l+r)>>1;
if(x<=mid)modify(k<<1,l,mid,x,y,v);
if(mid<y)modify(k<<1|1,mid+1,r,x,y,v);
push_up(k);
}
long long query(long long k,long long l,long long r,long long pos)
{
if(l==r)return sum[k];
push_down(k,l,r);
long long mid=(l+r)>>1;
if(pos<=mid)return query(k<<1,l,mid,pos);
else return query(k<<1|1,mid+1,r,pos);
}
void dfs1(long long x,long long fa,long long pre)
{
s[x]=1,f[x][0]=fa;
d[x]=d[fa]+1,dis[x]=dis[fa]+pre;
for(long long i=head[x];i;i=nxt[i])
{
long long y=to[i];
if(y==fa)continue;
dfs1(y,x,len[i]);
s[x]+=s[y];
if(s[y]>s[son[x]])son[x]=y;
}
}
void dfs2(long long x,long long topf)
{
id[x]=++idcnt,top[x]=topf;
if(!son[x])return;
dfs2(son[x],topf);
for(long long i=head[x];i;i=nxt[i])
{
long long y=to[i];
if(y==f[x][0] || y==son[x])continue;
dfs2(y,y);
}
}
void modify_seq(long long x,long long y)
{
while(top[x]!=top[y])
{
if(d[top[x]]<d[top[y]])swap(x,y);
modify(1,1,n,id[top[x]],id[x],1);
x=f[top[x]][0];
}
if(d[x]>d[y])swap(x,y);
modify(1,1,n,id[x],id[y],1);
}
void dfs(long long x,long long fa)
{
// printf("dfs %lld\n",x);
c[++tot]=x;
long long l=1,r=tot-1;
if(x==1 || dis[x]-dis[fa]>a[x])goto GG;
while(l<r)
{
long long mid=(l+r)>>1;
if(dis[x]-dis[c[mid]]<=a[x])r=mid;
else l=mid+1;
}
// printf("check %lld %lld\n",c[l],c[tot-1]);
modify_seq(c[l],c[tot-1]);
GG:
for(long long i=head[x];i;i=nxt[i])
{
long long y=to[i];
if(y==fa)continue;
dfs(y,x);
}
--tot;
}
int main()
{
// freopen("in.txt","r",stdin);
n=read();
for(long long i=1;i<=n;++i)
a[i]=read();
for(long long i=2;i<=n;++i)
{
long long x=read(),c=read();
addedge(x,i,c),addedge(i,x,c);
}
dfs1(1,0,0);
dfs2(1,1);
dfs(1,0);
for(long long i=1;i<=n;++i)
{
long long tmp=query(1,1,n,id[i]);
printf("%lld\n",tmp);
}
return 0;
}