codeforces 936(Div3) C.Tree Cutting

c o d e f o r c e s   936 ( D i v 3 )   C . T r e e C u t t i n g \Huge{codeforces~936(Div3)~C.Tree Cutting} codeforces 936(Div3) C.TreeCutting

题目链接:Problem - C - Codeforces

题意

给出一颗有 n n n个节点的,然后给出 n − 1 n-1 n1条边的情况。然后给出一个 k k k,要求删掉树中的 k k k条边,要求删掉边后的节点最少的子树的节点数最多 ( 1 ≤ k < n ≤ 1 0 5 ) (1\le k < n \le 10^5) (1k<n105)

思路

根据题意,题目要求节点最少的子树的节点数最多,那么当为结果 r e s res res时, r e s − 1 , r e s − 2 … res-1,res-2… res1,res2也可以通过删边得到。所以结果满足单调性,考虑使用二分

由于是树形结构,我们可以假设在每个点保存其后代节点的个数,表示以当前点作为根节点时子树大小。

那么如果结果为res时,我们首先应该将节点个数大于等于res的最小值的子树剪掉。

但是这个思路实现过程中,如果通过最后剪了 k k k次之后最小子树是否为 r e s res res来判断,比较难以实现。

因此,考虑当只有子树符合要求时剪去,否则不剪,若最后剪的次数大于等于 k k k,则当前 r e s res res满足要求,二分中间值应缩小。

标程

int n, k;
vector<int> a[N];

bool check(int mid) {
    int t = 0;

    auto dfs = [&](auto self, int x, int y) -> int {
        int sum = 1;
        for(auto i : a[x]) {
            if(i == y) continue;
            sum += self(self, i, x);//从叶子节点向上返回节点个数
        }
        if(sum >= mid && x != y) t ++, sum = 0;//如果个数符合就将其剪去,可以用向上返回0实现
        return sum;
    };

    int x = dfs(dfs, 1, 1);
    if(t > k || (t == k && x >= mid)) return true;
    else return false;
}

void Solved() {
    cin >> n >> k;
    for(int i = 1; i <= n; i ++ ) a[i].clear();//init
    for(int i = 1; i < n; i ++ ) {
        int x, y; cin >> x >> y;
        a[x].push_back(y); a[y].push_back(x);
    }
    
    int l = 1, r = n / (k + 1) + 1, mid;
    while(r - l > 1) {
        mid = l + r >> 1;   
        if(check(mid)) l = mid;
        else r = mid;
    }

    cout << l << endl;
}
  • 17
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值