20260606 - 部分分训练 2 总结

\(20pts\)\(m = 1\)

因为只要选一条,所以直接选直径即可。

\(40pts\)\(b_i = a_i + 1\)

链的情况直接二分答案即可。

\(55pts\)\(a_i = 1\)

菊花的情况只有两种:

  • 单独一条链
  • 和另一条链合并
    可以二分长度,搜索时可以用一个 \(multiset\) 来维护第一个比它大的,然后注意迭代器的问题。

\(80pts\):分支 \(\le 3\)

除根节点外,至多只有 \(2\) 个儿子,那么只有 \(2\) 种情况。

  1. 从儿子的最长路连上去
  2. 两个儿子连上
    显然,如果两个儿子能连上,就一定会连,不然会挤占其他点的生存空间。

\(100pts\):没有特殊性质

我们发现,把儿子配对的最长路看作一个点,就是 \(a_i = 1\) 的做法了。

维护一个 \(multiset\),然后每次加入点,配对完了就删掉。

注意迭代器。

#include <bits/stdc++.h>

using namespace std;
#define debug(x) cout<<#x<<' '<<x<<'\n';
#define ll long long
#define ull unsigned long long
#define db double
#define all(x) (x).begin(), (x).end()
#define inf (1 << 30)
#define lnf (1LL << 60)
typedef pair<int, int> PII;
constexpr int N = 5e4 + 7;
constexpr int P = 998244353;

int n, m;
vector<PII> adj[N]; // 注意大小

int f[N], g[N];

void dfs(int u, int from, ll mid) {
    g[u] = 0;
    multiset<int> nums;
    for (auto nxt : adj[u]) {
        int v = nxt.first, w = nxt.second;
        if (v == from) continue;
        dfs(v, u, mid);
        g[u] += g[v];
        if (f[v] + w >= mid) {
            ++g[u];
        } else {
            nums.insert(f[v] + w);
        }
    }
    for (auto it = nums.begin(); it != nums.end(); ) {
        auto ir = nums.lower_bound(mid - *it);
        if (ir == it) ++ir;
        if (ir != nums.end()) {
            nums.erase(ir);
            it = nums.erase(it);
            ++g[u];
        } else {
            ++it;
        }
    }
    if (nums.empty()) f[u] = 0;
    else f[u] = *prev(nums.end());
}

void solve() {
    auto check = [&](ll mid) -> bool {
        dfs(1, 0, mid);
        return g[1] >= m;
    };
    ll L = 0, R = 1e9;
    while (L < R) {
        ll mid = (L + R + 1) / 2;
        if (check(mid)) L = mid;
        else R = mid - 1; 
    }
    printf("%lld\n", L);
}

int main() {
    scanf("%d%d", &n, &m);
    for (int i = 1; i < n; i++) {
        int u, v, w;
        scanf("%d%d%d", &u, &v, &w);
        adj[u].push_back({v, w});
        adj[v].push_back({u, w});
        if (u != 1) mark1 = false;
        if (v != u + 1) mark2 = false;
    }
    solve();
    return 0;
}

posted @ 2026-06-07 14:20  AKCoder  阅读(13)  评论(0)    收藏  举报