树上贪心+二分

树上贪心+二分

题目描述

牛客周赛 Round 85

小紫的树上染色

​ 小红拿到了一棵由 \(n\)个节点组成的树,她已经把所有节点都染成了红色。这时,小紫准备将 k 个节点染成紫色,使得最大红色连通块的大小尽可能小。你能帮帮她吗?

$ \hspace{15pt}$对于树上的两个点,如果它们均为红色且相连,则称他们位于同一个红色连通块里。特别地,一个单独的点也构成一个红色连通块。连通块的大小即为连通块中节点的数量。

输入描述

\(\hspace{15pt}\)第一行输入两个正整数$ n,k(1≦k≦n≦105)\(,代表节点数量和小紫准备染色的次数。 \)\hspace{15pt}$此后 \(n−1\)行,第 iii 行输入两个正整数$ u_i,v_i(1≦u_i,v_i≦n)$,代表第 \(i\)条边连接节点\(u_i\) 和节点 \(v_i\)。保证输入的图是一棵树。

输出描述

一个整数,代表最大红色连通块大小的最小值。特殊的,如果不存在红色连通块,请输出 0。

题解

因为题目给定的加粗信息,要求的是一个最大值的最小值,很明显我们要往二分方向想

又因为k次最大ans,则k + 1次一定是 <= ans,满足单调性

  1. 二分最大连通块的数量mid
  2. 跑一遍DFS,以1节点为根节点,后序遍历,求出每个点的孩子节点个数,如果该点 > mid,则染为紫色= 0
  3. 最后输出二分的结果

这里要注意的是,dfs遍历的时候无论以那个点为根节点都可以,因为染色的点是固定的

贪心的思想就是,尽量不染叶子节点。

#include <bits/stdc++.h>
#define fi first
#define se second
#define pb push_back
#define ppb pop_back
#define SZ(v) ((int)v.size())
#define pii pair<int, int>
#define int long long
#define all(v) v.begin(), v.end()
#define debug(x) cout << "======" << x << "========" << "\n"
typedef long long ll;
typedef unsigned int u32;
typedef unsigned long long u64;
typedef double db;
using namespace std;
const int N = 1e6+10;
const int mod = 1e9+7;
int _;

int n, k;

void solve() {
    cin >> n >> k;
    vector<vector<int>> e(n+1);
    for(int i = 0, u, v; i < n - 1; i++) {
        cin >> u >> v;
        e[u].pb(v);
        e[v].pb(u);
    }

    auto check = [&] (int m) {
        int need = 0;
        vector<int> sz(n + 1, 0);
        function<void(int, int)> dfs = [&] (int u, int fa) {
            for(int v : e[u]) {
                if(v == fa) continue;
                dfs(v, u);
                sz[u] += sz[v];
            }
            sz[u]++;
            if(sz[u] > m) {
                sz[u] = 0;
                need++;
            }
        };
        dfs(1, 0);
        return need <= k;
    };

    int l = 0, r = n;
    int ans = 0;
    while(l <= r) {
        int m = (l + r) >> 1;
        if(check(m)) {
            ans = m;
            r = m - 1;
        } else {
            l = m + 1;
        }
    }
    cout << ans;
}

signed main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    _ = 1;
    // cin >> _;
    
    while(_--) {
        solve();
    } 
    return 0;
}
posted @ 2025-03-18 23:19  Evan619  阅读(33)  评论(0)    收藏  举报