1 条题解
-
0
#include <iostream> #include <vector> #include <algorithm> #include <cstring> using namespace std; const int MAXN = 10010; int N, K; vector<pair<int, int>> graph[MAXN]; bool deleted[MAXN]; int sz[MAXN]; // 计算子树大小 int calcSize(int u, int p) { sz[u] = 1; for (auto &e : graph[u]) { int v = e.first; if (v == p || deleted[v]) continue; sz[u] += calcSize(v, u); } return sz[u]; } // 找重心 void findCentroid(int u, int p, int tot, int ¢roid, int &best) { int maxSub = 0; for (auto &e : graph[u]) { int v = e.first; if (v == p || deleted[v]) continue; findCentroid(v, u, tot, centroid, best); maxSub = max(maxSub, sz[v]); } maxSub = max(maxSub, tot - sz[u]); if (maxSub < best) { best = maxSub; centroid = u; } } // 收集距离 void collectDist(int u, int p, int dist, vector<int> &ds) { ds.push_back(dist); for (auto &e : graph[u]) { int v = e.first; int w = e.second; if (v == p || deleted[v]) continue; collectDist(v, u, dist + w, ds); } } // 计算距离数组中有多少对 (i<j) 满足 d[i]+d[j] <= K int countPairs(vector<int> &ds) { sort(ds.begin(), ds.end()); int cnt = 0; int j = (int)ds.size() - 1; for (int i = 0; i < ds.size(); ++i) { while (j > i && ds[i] + ds[j] > K) --j; if (j > i) cnt += (j - i); else break; } return cnt; } // 点分治主函数 int solve(int u) { // 计算当前连通块的大小 calcSize(u, -1); int centroid = u; int best = MAXN; // 寻找重心 findCentroid(u, -1, sz[u], centroid, best); deleted[centroid] = true; int ans = 0; // 存储所有节点到重心的距离 vector<int> allDist; allDist.push_back(0); // 重心自身距离为0 // 处理每个子树 for (auto &e : graph[centroid]) { int v = e.first; int w = e.second; if (deleted[v]) continue; vector<int> subDist; collectDist(v, centroid, w, subDist); // 减去同一子树内组合的路径 ans -= countPairs(subDist); // 合并到总距离列表 allDist.insert(allDist.end(), subDist.begin(), subDist.end()); } // 加上所有组合的路径 ans += countPairs(allDist); // 递归处理各子树 for (auto &e : graph[centroid]) { int v = e.first; if (!deleted[v]) { ans += solve(v); } } return ans; } int main() { while (scanf("%d%d", &N, &K) == 2) { if (N == 0 && K == 0) break; // 初始化 for (int i = 0; i < N; ++i) { graph[i].clear(); deleted[i] = false; } // 读入树 for (int i = 0; i < N - 1; ++i) { int u, v, l; scanf("%d%d%d", &u, &v, &l); graph[u].push_back({v, l}); graph[v].push_back({u, l}); } int ans = solve(0); printf("%d\n", ans); } return 0; }
信息
- ID
- 163
- 时间
- 1000ms
- 内存
- 128MiB
- 难度
- 10
- 标签
- 递交数
- 3
- 已通过
- 1
- 上传者