版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_39972971/article/details/84983451
【题目链接】
【思路要点】
- 首先,二分答案 ,问题转化为判断是否存在 条长度大于等于 的边不相交的路径,考虑树形 。
- 记 为一个二元组 ,表示在点 的子树中至多可以选出 条路径,并且在选出 条路径的基础上,根节点处还可以引出一条长度为 的不与其余路径相交的路径。
- 转移时我们需要考虑的问题入下:给定数组 ,我们需要选出尽可能多的和大于等于 的数对,在最大化选出对数的情况下,最大化没有被选中的数的最小值。
- 考虑如下贪心,对 排序,从小到大考虑每一个数 ,令当前数组中剩余的最大值为 ,若 ,那么 无法配对,其用途只能是留作没有被选中的数;否则,令当前数集中最小的满足 的 ,将 和 配对一定是最优的。
- 该过程可以用栈来模拟。
- 时间复杂度 。
【代码】
#include<bits/stdc++.h> using namespace std; const int MAXN = 1e5 + 5; template <typename T> void read(T &x) { x = 0; int f = 1; char ch = getchar(); for (; !isdigit(ch); ch = getchar()) if (ch == '-') f = -f; for (; isdigit(ch); ch = getchar()) x = x * 10 + ch - '0'; x *= f; } struct info {int ans, res; }; struct edge {int dest, len; }; vector <edge> a[MAXN]; int n, m, mid; info dp[MAXN]; info operator + (info a, int b) { a.res += b; if (a.res >= mid) { a.ans++; a.res = 0; } return a; } int tot, len[MAXN], q[MAXN]; int top, fa[MAXN], s[MAXN]; void bfs(int from) { memset(fa, -1, sizeof(fa)); int l = 1, r = 1; fa[1] = 0; q[1] = from; while (l <= r) { int pos = q[l++]; for (unsigned i = 0; i < a[pos].size(); i++) if (fa[a[pos][i].dest] == -1) { fa[a[pos][i].dest] = pos; q[++r] = a[pos][i].dest; } } } void work() { for (int p = n; p >= 1; p--) { int pos = q[p]; tot = 0; dp[pos] = (info) {0, 0}; for (unsigned i = 0; i < a[pos].size(); i++) if (a[pos][i].dest != fa[pos]) { info tmp = dp[a[pos][i].dest] + a[pos][i].len; dp[pos].ans += tmp.ans, len[++tot] = tmp.res; } sort(len + 1, len + tot + 1); top = 0; for (int i = 1, j = tot + 1; i <= tot; i++) { while (j - 1 > i && len[i] + len[j - 1] >= mid) s[++top] = --j; if (i + 1 >= j) { s[++top] = i; dp[pos].ans += top / 2; if (top % 2 == 1) dp[pos].res = max(dp[pos].res, len[s[1]]); break; } else if (top != 0) top--, dp[pos].ans++; else dp[pos].res = max(dp[pos].res, len[i]); } } } int main() { freopen("track.in", "r", stdin); freopen("track.out", "w", stdout); read(n), read(m); for (int i = 1; i <= n - 1; i++) { int x, y, z; read(x), read(y), read(z); a[x].push_back((edge) {y, z}); a[y].push_back((edge) {x, z}); } bfs(1); int l = 1, r = 1e4 * n; while (l < r) { mid = (l + r + 1) / 2; work(); if (dp[1].ans >= m) l = mid; else r = mid - 1; } printf("%d\n", l); return 0; }