题目大意:一棵树有
n(n≤2∗105)
个点,编号为
1−n
,固定
1
号节点为根。每个点有一个值
题解:比较容易想到,对于每一个点
i
,二分它的祖先节点,找到第一个到
//= = 不该用倍增的
#include <bits/stdc++.h>
using namespace std;
const int maxn = 200020;
typedef long long ll;
struct node{
int v;
int val;
node(int v,int val):v(v),val(val){}
node(){}
bool operator < (const node & a) const{
return val>a.val;
}
};
vector<node> T[maxn];
int pa[maxn][20];
ll dis[maxn];
int dep[maxn];
int a[maxn];
int ans[maxn];
node po[maxn];
void dfs(int u){
ll d = dis[u];
for(int i = 0;i < T[u].size();i++){
int v = T[u][i].v;
dis[v] = d + T[u][i].val;
dep[v] = dep[u] + 1;
dfs(v);
}
}
int findfa(int u,int d){
int x = u;
for(int i = 19;i >=0 && d;i--){
if((1<<i)<=d){
x = pa[x][i];
d -= (1<<i);
}
}
return x;
}
int main(){
int n;
scanf("%d",&n);
for(int i = 1;i <= n;i++){
scanf("%d",&a[i]);
}
int p,w;
dis[1] = 0;
dep[1] = 0;
memset(pa,-1,sizeof(pa));
memset(ans,0,sizeof(ans));
pa[1][0] = 0;
for(int i = 2;i <= n;i++){
scanf("%d%d",&p,&w);
T[p].push_back(node(i,w));
pa[i][0] = p;
}
dfs(1);
po[0].v = 0;
po[0].val = -1;
for(int i = 1;i <= n;i++){
po[i].v = i;
po[i].val = dep[i];
}
for(int j = 1;j < 20;j++){
for(int i = 1;i <= n;i++){
if(~pa[i][j-1])
pa[i][j] = pa[pa[i][j-1]][j-1];
}
}
sort(po,po+1+n);
for(int i = 2;i <= n;i++){
int l = 0,r = dep[i],mid;
while(l < r){
mid = (l+r+1)>>1;
if(dis[i]-dis[findfa(i,mid)]>a[i]) r = mid-1;
else l = mid;
}
int t = pa[findfa(i,l)][0];
ans[pa[i][0]]++;
ans[t]--;
}
for(int i = 0;i <= n;i++){
int v,p;
v = po[i].v;
p = pa[v][0];
if(p != -1){
ans[p] += ans[v];
}
}
for(int i = 1;i <= n;i++){
printf("%d",ans[i]);
if(i == n) printf("\n");
else printf(" ");
}
return 0;
}