【题目链接】
【三倍经验链接】
【思路要点】
- 二分答案,在点分树内查询小于答案的路径条数。
- 时间复杂度\(O(NLog^3N)\)。
【代码】
#include<bits/stdc++.h> using namespace std; #define MAXN 100005 template <typename T> void read(T &x) { x = 0; int f = 1; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == '-') f = -f; for (; isdigit(c); c = getchar()) x = x * 10 + c - '0'; x *= f; } vector <int> dest[MAXN], len[MAXN], a[MAXN]; vector <int> vroot[MAXN], vson[MAXN]; map <int, int> mp[MAXN]; int n, k, root, cntpoints; int size[MAXN], weight[MAXN]; int father[MAXN]; bool visited[MAXN]; void chkmax(int &x, int y) { x = max(x, y); } void getroot(int pos, int fa) { size[pos] = 1; weight[pos] = 0; for (unsigned i = 0; i < dest[pos].size(); i++) { if (dest[pos][i] == fa || visited[dest[pos][i]]) continue; getroot(dest[pos][i], pos); size[pos] += size[dest[pos][i]]; chkmax(weight[pos], size[dest[pos][i]]); } chkmax(weight[pos], cntpoints - size[pos]); if (weight[pos] < weight[root]) root = pos; } void calsize(int pos, int fa) { size[pos] = 1; for (unsigned i = 0; i < dest[pos].size(); i++) { if (dest[pos][i] == fa || visited[dest[pos][i]]) continue; calsize(dest[pos][i], pos); size[pos] += size[dest[pos][i]]; } } void getvroot(int root, int pos, int fa, int dist) { vroot[root].push_back(dist); mp[root][pos] = dist; for (unsigned i = 0; i < dest[pos].size(); i++) { if (visited[dest[pos][i]] || dest[pos][i] == fa) continue; getvroot(root, dest[pos][i], pos, dist + len[pos][i]); } } void getvson(int root, int pos, int fa, int dist) { vson[root].push_back(dist); for (unsigned i = 0; i < dest[pos].size(); i++) { if (visited[dest[pos][i]] || dest[pos][i] == fa) continue; getvson(root, dest[pos][i], pos, dist + len[pos][i]); } } void work(int pos) { visited[pos] = true; calsize(pos, 0); getvroot(pos, pos, 0, 0); for (unsigned i = 0; i < dest[pos].size(); i++) { if (visited[dest[pos][i]]) continue; root = 0; cntpoints = size[dest[pos][i]]; getroot(dest[pos][i], pos); a[pos].push_back(root); father[root] = pos; getvson(root, dest[pos][i], 0, len[pos][i]); work(root); } } int query(vector <int> &a, int value) { int l = -1, r = a.size() - 1; while (l < r) { int mid = (l + r + 1) / 2; if (a[mid] <= value) l = mid; else r = mid - 1; } return l + 1; } int count(int pos, int value) { int ans = query(vroot[pos], value); int p = father[pos], q = pos; while (p != 0) { ans -= query(vson[q], value - mp[p][pos]); ans += query(vroot[p], value - mp[p][pos]); q = p; p = father[p]; } return ans; } int main() { read(n), read(k); int maxv = 0; for (int i = 1; i <= n - 1; i++) { int x, y, z; read(x), read(y), read(z); chkmax(maxv, z); dest[x].push_back(y); dest[y].push_back(x); len[x].push_back(z); len[y].push_back(z); } weight[0] = n + 1; root = 0; cntpoints = n; getroot(1, 0); work(root); for (int i = 1; i <= n; i++) { sort(vroot[i].begin(), vroot[i].end()); sort(vson[i].begin(), vson[i].end()); } for (int i = 1; i <= n; i++) { int l = 0, r = maxv * n; while (l < r) { int mid = (l + r) / 2; if (count(i, mid) <= k) l = mid + 1; else r = mid; } printf("%d\n", l); } return 0; }