我的思路和题解里面的思路是一样的,就是利用类似在线LCA的倍增思想求距离节点u的最远祖先,然后求树上差分。
下面是我的代码,请各位大佬帮忙看看哪里错了,我会发送 5 块钱红包作为感谢:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 2e5 + 5;
/**
a[i] 节点i的权值
w[i] 节点i连向其父节点的那条边的边权
f[i][j] 节点i的深度比它小2^j的祖先借点(不存在则为1)
cnt[i] 树上倍增所需的差分数组
dis[i] 节点i与根节点的距离
*/
int n, a[maxn], w[maxn], f[maxn][21], cnt[maxn];
long long dis[maxn];
vector<int> g[maxn];
/**
u 当前节点, p父节点, d当前节点距离根节点的路径长度
*/
void dfs1(int u, int p, long long d) {
dis[u] = d;
f[u][0] = p;
for (auto v : g[u])
dfs1(v, u, d + w[v]);
}
/**
用倍增思路求解节点u的距离他不超过a[u]的最远祖先节点编号
*/
int getid(int u) {
long long d = dis[u] - a[u];
for (int i = 20; i >= 0; i--) {
int p = f[u][i];
if (dis[p] >= d) u = p;
}
return u;
}
/**
树上差分,类似求前缀和
*/
void dfs2(int u) {
for (auto v : g[u]) {
dfs2(v);
cnt[u] += cnt[v];
}
}
int main() {
cin >> n;
for (int i = 1; i <= n; i++) cin >> a[i];
for (int v = 2; v <= n; v++) {
int u;
cin >> u >> w[v];
g[u].push_back(v);
}
dfs1(1, 1, 0);
for (int u = 1; u <= n; u++)
for (int i = 1; i <= 20; i++)
f[u][i] = f[ f[u][i-1] ][i-1];
for (int u = 2; u <= n; u++) {
int pp = getid(u);
if (pp == u) continue;
if (u != 1) cnt[f[u][0]]++;
if (pp != 1) cnt[f[pp][0]]--;
}
dfs2(1);
for (int i = 1; i <= n; i++) cout << cnt[i] << " ";
return 0;
}