思路是对于每一个结点 u,二分找最多有几个祖先能够控制 u,然后用树上差分维护祖先能控制的结点数。整个的复杂度应该(?)是 O(n(logn)2) 的,但是 TLE 了。
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using ld = long double;
struct Edge { ll to, w; };
ll n, sum;
ll fa[200005][20], lvl[200005], a[200005], dis[200005], c[200005];
vector <Edge> G[200005];
void dfs(ll cur, ll p) {
lvl[cur] = lvl[p] + 1;
fa[cur][0] = p;
for (int i = 1; i <= 19; i++) fa[cur][i] = fa[fa[cur][i - 1]][i - 1];
for (auto v : G[cur]) {
if (v.to == p) continue;
dis[v.to] = dis[cur] + v.w;
dfs(v.to, cur);
}
}
ll LCA(ll u, ll v) {
if (lvl[u] < lvl[v]) swap(u, v);
for (int i = 19; i >= 0; i--) {
if ((lvl[u] - lvl[v] >> i) & 1) u = fa[u][i];
}
if (u == v) return u;
for (int i = 19; i >= 0; i--) {
if (fa[u][i] != fa[v][i]) u = fa[u][i], v = fa[v][i];
}
return fa[u][0];
}
ll DIS(ll u, ll v) { return dis[u] + dis[v] - 2 * dis[LCA(u, v)]; }
ll pr(ll u, ll k) {
for (int i = 19; i >= 0; i--) {
if ((k >> i) & 1) u = fa[u][i];
}
return u;
}
void dfs_sum(ll cur, ll p) {
for (auto v : G[cur]) {
if (v.to == p) continue;
dfs_sum(v.to, cur);
c[cur] += c[v.to];
}
}
int main() {
ios :: sync_with_stdio(0);
cin >> n;
for (int i = 1; i <= n; i++) cin >> a[i];
for (int i = 1; i < n; i++) {
ll p, w;
cin >> p >> w;
G[i + 1].push_back({p, w});
G[p].push_back({i + 1, w});
}
lvl[0] = -1;
dfs(1, 0);
for (int i = 1; i <= n; i++) {
ll l = 0, r = lvl[i];
while (l <= r) {
ll mid = l + r >> 1;
if (DIS(pr(i, mid), i) <= a[i]) {
sum = mid;
l = mid + 1;
}
else r = mid - 1;
}
// cout << i << ' ' << pr(i, sum) << '\n';
if (pr(i, sum) != i) {
ll p = fa[i][0];
c[p]++, c[pr(i, sum)]++;
c[LCA(p, pr(i, sum))]--, c[fa[LCA(p, pr(i, sum))][0]]--;
}
}
dfs_sum(1, 0);
for (int i = 1; i <= n; i++) cout << c[i] << ' ';
return 0;
}