【ARC116E】Spread of Information 题解 (二分 + 贪心)

AtC 传送门:ARC116E Spread of Information

二分 + 贪心。

题意

一个城市是由 n 个点 n1 条边组成的树,一个点的危险度是指这个点到任意一个消防站的距离的最小值。现在要选择 k 个点建立消防站,使得所有点的危险度的最大值最小,求这个值。

Solution

看到“最大值最小”,思考二分答案的做法。显然,二分的是所有节点危险度的最大值。

不难想到,check(mid) 函数考虑使用贪心实现。从叶子节点往根节点,如果一个节点到自己子树内的 最远未覆盖子节点 的距离刚好超过了 mid,那么这个节点就必须得放一个消防站。

大致求解的思路如上,具体 check() 函数的写法、最远未覆盖子节点的维护等等详见代码及注释。

Code


 
#include<bits/stdc++.h>
using namespace std;
 
#define rep(i, a, b) for(register int i = a; i <= b; ++i)
const int maxn = 2e5 + 5;
int n, k, f[maxn], g[maxn];
int cnt, hd[maxn];
int rt, mx, siz[maxn];
struct node{
    int to, nxt;
}e[maxn << 1];
inline void add(int u, int v){
    e[++cnt] = (node){v, hd[u]}, hd[u] = cnt;
}
bool vis[maxn];
 
inline int dfs(int u, int fa, int dis){
    int res = 0, flg = 0; f[u] = 1e9, g[u] = -1e9;
    for(int i = hd[u]; i; i = e[i].nxt){
        int v = e[i].to; if(v == fa) continue;
        res += dfs(v, u, dis), flg = 1;
        f[u] = min(f[u], f[v] + 1),// f 数组维护的是每个节点的危险度 
		g[u] = max(g[u], g[v] + 1);//g[u] 表示节点 u 到自己最远未覆盖子节点的距离 
    }
    if(f[u] + g[u] <= dis) g[u] = -1e9;
	//如果 u 的子树内最近的消防站到 u 子树内最深为覆盖子节点的距离 <= dis 那么 u 及其子树一定可以被覆盖 
    if(!flg or f[u] == dis + 1) g[u] = max(g[u], 0);
	//u 没有被覆盖,等祖先中某一个节点安装消防站将其覆盖 
    if(g[u] == dis)//需要在 u 建立一个消防站 
        res += 1, f[u] = 0, g[u] = -1e9;
    return res;
}
 
inline bool chck(int x){
    return (dfs(1, 0, x) + (g[1] >= 0)/*还需要在根节点安装消防站*/) <= k;
}
 
int main(){
    scanf("%d%d", &n, &k);
    if(k >= n){printf("0\n"); return 0;}
    rep(i, 2, n){
        int u, v; scanf("%d%d", &u, &v);
        add(u, v), add(v, u);
    }
    int l = 1, r = n;
    while(l < r){
        int mid = l + r >> 1;
        if(chck(mid)) r = mid; else l = mid + 1;
    }
    printf("%d\n", l);
    return 0;
}

posted @   pldzy  阅读(124)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示