【ARC116E】Spread of Information 题解 (二分 + 贪心)
AtC 传送门:ARC116E Spread of Information
二分 + 贪心。
题意
一个城市是由
Solution
看到“最大值最小”,思考二分答案的做法。显然,二分的是所有节点危险度的最大值。
不难想到,check(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;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】