主要是运用树状数组快速区间求和,还有dfs求距离,记录点的顺序,该点的子树最远的叶子;
#include<bits/stdc++.h>
using namespace std;
#define pb(a) push_back(a)
#define LL long long
const int maxn = 2e5+5;
int a[maxn],in[maxn],out[maxn],c[maxn],ans[maxn]; //a-每个点的值,in-dfs该点的顺序,out-该点的子树最远的叶子
LL dis[maxn]; //每个点到根的距离
vector<int> g[maxn],w[maxn]; //g-建树,w-每条边的值
int n,ord = 0;
struct node {
int tp,id;
LL v;
} b[maxn*2];
bool cmp(node a,node b) {
if(a.v == b.v) return a.tp < b.tp;
return a.v < b.v;
}
void dfs(int x,LL d) { //dfs in-标记每个点遍历的顺序,out-该点的子树最远的叶子,dis-该点到根节点的距离
dis[x] = d;
in[x] = ++ord;
for(int i = 0;i < g[x].size();i++) {
dfs(g[x][i],d+w[x][i]);
}
out[x] = ord;
}
void add(int x) {
while(x <= n) {
c[x]++;
x += x&-x; //lowbit直接写在函数里面,看起来简洁些
}
}
int query(int x) {
int ans = 0;
while(x) {
ans += c[x];
x -= x&-x;
}
return ans;
}
int main() {
scanf("%d",&n);
for(int i = 1;i <= n;i++) scanf("%d",&a[i]);
for(int i = 2;i <= n;i++) {
int u,v;
scanf("%d%d",&u,&v);
g[u].pb(i);
w[u].pb(v);
}
dfs(1,0);
int cnt = 0;
for(int i = 1;i <= n;i++) {
b[++cnt] = (node){1,i,dis[i]-a[i]};
b[++cnt] = (node){2,i,dis[i]};
}
//for(int i = 1;i <= cnt;i++) printf("%d %d %I64d\n",b[i].tp,b[i].id,b[i].v);
sort(b+1,b+1+cnt,cmp);
memset(c,0,sizeof(c));
for(int i = 1;i <= cnt;i++) {
if(b[i].tp == 1) add(in[b[i].id]);
else {
ans[b[i].id] = query(out[b[i].id]) - query(in[b[i].id] - 1);
}
}
for(int i = 1;i <= n;i++)
printf("%d ",ans[i]-1); //得到的答案包含它本身,所以要减一
puts("");
}