給定 n 節點樹(n ≤ 10,000),邊有長度。求節點對 (u,v) 使得 dist(u,v) ≤ k 的數量。多測試用例,以 0 0 結束。
void getDist(int u, int fa, int dis) {
if (dis > k) return;
dist[tot++] = dis;
for (auto e = head[u]; e; e = e->next)
if (e->v != fa && !vis[e->v])
getDist(e->v, u, dis + e->len);
}
void countPairs(int u) { // 不同子樹
sort(dist, dist + tot);
int l = 0, r = tot - 1;
while (l < r) {
if (dist[l] + dist[r] <= k) ans += r - l, ++l;
else --r;
}
}
void solve(int u) {
int centroid = getCentroid(u);
tot = 0; getDist(centroid, 0, 0); countPairs(centroid);
vis[centroid] = 1;
for (auto e = head[centroid]; e; e = e->next)
if (!vis[e->v]) {
tot = 0; getDist(e->v, centroid, e->len);
sort(dist, dist + tot);
int l = 0, r = tot - 1;
while (l < r) { // 同子樹內減去
if (dist[l] + dist[r] <= k) ans -= r - l, ++l;
else --r;
}
solve(e->v);
}
}
每層分治 O(n log n),深度 O(log n),總體 O(n log² n),n=10,000 輕鬆通過。