CF1739D Reset K Edges rating1900

文章描述了一种针对有根树的问题,目标是在不超过k次操作中使树的高度最小。每次操作可以删除一条边并添加一条连接根节点的边。解决方案是使用二分查找来确定最小高度,在这个过程中从叶子节点向上遍历,更新每个节点的最大深度,并检查是否需要进行操作。代码示例给出了C++实现。
摘要由CSDN通过智能技术生成

题目描述:

给出1~n的有根树,删除任意边(v,u),添加一条(1,u)为一次操作,要求在至多k次操作内,树的高度(定义为树的最大深度)最小。

输入:

t组测试数据(1<t<1e4)

点数n,操作次数k(2<=n<=2e5,0<=k<=n-1)

pi表示节点i的父节点为i p2,p3,p4……pn(1<pi<i,2<=i<=n)

输出:

k次操作后最小的树的高度

Solution:

由于题目是求最大值中的最小值问题,故此处我们可以采用二分的解法,对于树的高度进行二分,判断在每次树高为mid的情况下,所需的操作次数res与k进行比较。

而求res的过程中,我们只需要遍历每个节点的最大深度,同时判断子节点的最大深度是否满足要求,如果满足则res++,否则更新父节点的最大深度。

C++Code:

#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10, M = 4e5 + 10;
int n, k;
int res = 0;
int h[N], e[M], ne[M], idx = 0;
map<int, int>m;
void add(int a, int b) {
    e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}
void dfs(int u,int mid) {//遍历每个节点的最大深度,计算操作次数
    for (int i = h[u]; i != -1; i = ne[i]) {
        int j = e[i];
        dfs(j, mid);
        if (m[j] + 1 == mid)res++;//如果子节点符合要求便res++
        else m[u] = max(m[u], m[j] + 1);//否则更新父节点的最大深度
    }
}
bool check(int mid) {
    res = 0;
    m.clear();
    for (int i = h[1]; i != -1; i = ne[i]) {//遍历节点1的子节点
        int j = e[i];
        dfs(j, mid);
    }
    return res <= k;
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int t;
    cin >> t;
    while (t--) {
        idx = 0;
        memset(h, -1, sizeof h);
        cin >> n >> k;
        for (int i = 2; i <= n; i++) {
            int b;
            cin >> b;
            add(b, i);
        }
        int l = 1, r = n - 1;
        while (l < r) {//二分
            int mid = l + r >> 1;
            if (check(mid))r = mid;
            else l = mid + 1;
        }
        cout << r << endl;
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值