NOIP2012疫情控制(二分答案+倍增+贪心)
Description
H国有n个城市,这n个城市用n-1条双向道路相互连通构成一棵树,1号城市是首都,也是树中的根节点。 H国的首都爆发了一种危害性极高的传染病。当局为了控制疫情,不让疫情扩散到边境城市(叶子节点所表示的城市),决定动用军队在一些城市建立检查点,使得从首都到边境城市的每一条路径上都至少有一个检查点,边境城市也可以建立检查点。但特别要注意的是,首都是不能建立检查点的。 现在,在H国的一些城市中已经驻扎有军队,且一个城市可以驻扎多个军队。一支军队可以在有道路连接的城市间移动,并在除首都以外的任意一个城市建立检查点,且只能在一个城市建立检查点。一支军队经过一条道路从一个城市移动到另一个城市所需要的时间等于道路的长度(单位:小时)。 请问最少需要多少个小时才能控制疫情。注意:不同的军队可以同时移动。
\(Hint:2≤m≤n≤50,000,0 < w <10^9\)
Solution
可以发现,军队可以同时移动,那么就是求最大值最小,考虑二分答案,
接下来可以发现,军队越往上,控制的点越多,那么显然,军队应该尽量往上爬,
在树上向上爬,那就倍增吧(_)
所以用贪心的思路,所有军队尽量往根节点爬,然后再考虑爬到一些没有军队的分支,
那么如果去支援分支,显然只要到根节点的某个子节点就能控制这个分支,
将向上能到达根节点的点存起来,用B数组储存,并且记录它是从根节点的哪个子节点上来的,因为可能不去支援其他点,就要返回到上一个点
而到不了根节点的点,保持在最高点为最优,将这个最高点标记,表示这个点被控制了,此时只有部分点被标记为控制的,
此时进行一个操作,对于一个非根节点的点,如果其子节点全被控制,那它也是被控制的,就这样从根节点遍历整棵树,记录所有被控制的点,用C数组储存
然后再考虑让可以到达根节点的点去支援没有被控制的根节点的子节点
接下来将没有被控制的根节点的子节点也存起来,然后将BC,2个数组按到根节点的距离排序
注意是从小到大!因为B数组要先考虑要不要返回上一个点,
然后判断是否C数组所有点都可以被控制即可
(_)终于打完了,真的麻烦,细节挺多的,主要错误如下:
- 向上跳的时候,应先更新距离再更新点的编号
- 预处理倍增时,应从\(2^1\)开始算,因为\(2^0\)已经算过了
- !!!倍增最大可以到50000,但我看成5000,只开到\(2^{14}\),导致大数据挂
看来我倍增还是不熟练
Code
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#define N 50010
using namespace std;
struct info {
int to, nex, w;
} e[N * 2];
int n, m, tot, head[N * 2], ans, arm[N], l, r;
int _log, f[N][20], dis[N][20];
struct node {
int d, fr;
} b[N], c[N];
bool flag[N];
bool cmp(node a, node b) {return a.d < b.d;}
inline int read() {
int x = 0, f = 1; char ch = getchar();
while (ch < '0' || ch > '9') {if (ch == '-')f = -1; ch = getchar();}
while (ch >= '0' && ch <= '9') {x = x * 10 + ch - '0'; ch = getchar();}
return x * f;
}
inline void add_edge(int u, int v, int w) {
e[++tot].to = v;
e[tot].nex = head[u];
head[u] = tot;
e[tot].w = w;
}
void dfs(int u, int fa) {
for (int j = 1; j <= _log; ++j) {
f[u][j] = f[f[u][j - 1]][j - 1];
dis[u][j] = dis[u][j - 1] + dis[f[u][j - 1]][j - 1];
}
for (int i = head[u]; i; i = e[i].nex) {
int v = e[i].to;
if (v == fa) continue;
f[v][0] = u;
dis[v][0] = e[i].w;
dfs(v, u);
}
}
void color(int u, int fa) {
int p = 1, q = 0;
for (int i = head[u]; i; i = e[i].nex) {
int v = e[i].to;
if (v == fa) continue;
color(v, u);
p &= flag[v];
q = 1;
}
if (p && q && u != 1)
flag[u] = 1;
}
bool check(int mid) {
memset(flag, 0, sizeof(flag));
int cnt = 0, top = 0;
for (int i = 1; i <= m; ++i) {
int u = arm[i], cos = 0;
for (int j = _log; j >= 0; --j)
if (f[u][j] && dis[u][j] + cos <= mid) {
cos += dis[u][j];
u = f[u][j];
}
if (u != 1) flag[u] = 1;
else {
b[++cnt].d = mid - cos;
u = arm[i];
for (int j = _log; j >= 0; j--)
if (f[u][j] > 1)
u = f[u][j];
b[cnt].fr = u;
}
}
color(1, 0);
for (int i = head[1]; i; i = e[i].nex) {
int v = e[i].to;
if (!flag[v]) {
c[++top].d = e[i].w;
c[top].fr = e[i].to;
}
}
sort(b + 1, b + cnt + 1, cmp);
sort(c + 1, c + top + 1, cmp);
int j = 1; c[top + 1].d = 1e9;
for (int i = 1; i <= cnt; ++i) {
if (!flag[b[i].fr]) flag[b[i].fr] = 1;
else if (b[i].d >= c[j].d) flag[c[j].fr] = 1;
while (flag[c[j].fr]) j++;
}
return j > top;
}
inline void Init() {
n = read();
_log = log(n) / log(2);
for (int i = 1; i < n; ++i) {
int u = read(), v = read(), w = read();
r += w;
add_edge(u, v, w);
add_edge(v, u, w);
}
m = read();
for (int i = 1; i <= m; ++i)
arm[i] = read();
}
int main() {
Init();
dfs(1, 0);
ans = -1;
while (l <= r) {
int mid = (l + r) >> 1;
if (check(mid))
ans = mid, r = mid - 1;
else l = mid + 1;
}
printf("%d\n", ans);
return 0;
}
NOIP2012疫情控制(二分答案+倍增+贪心)的更多相关文章
- NOIP2012疫情控制(二分答案+树上贪心)
H 国有n个城市,这 n个城市用n-1条双向道路相互连通构成一棵树,1号城市是首都,也是树中的根节点. H国的首都爆发了一种危害性极高的传染病.当局为了控制疫情,不让疫情扩散到边境城市(叶子节点所表示 ...
- luogu1084 [NOIp2012]疫情控制 (二分答案+倍增+dfs序)
先二分出一个时间,把每个军队倍增往上跳到不能再跳 然后如果它能到1号点,就记下来它跳到1号点后剩余的时间:如果不能,就让它就地扎根,记一记它覆盖了哪些叶节点(我在这里用了dfs序+差分,其实直接dfs ...
- [NOIP2012]疫情控制(二分答案+倍增+贪心)
Description H国有n个城市,这n个城市用n-1条双向道路相互连通构成一棵树,1号城市是首都,也是树中的根节点. H国的首都爆发了一种危害性极高的传染病.当局为了控制疫情,不让疫情扩散到边境 ...
- 洛谷P1084 疫情控制(NOIP2012)(二分答案,贪心,树形DP)
洛谷题目传送门 费了几个小时杠掉此题,如果不是那水水的数据的话,跟列队的难度真的是有得一比... 话说蒟蒻仔细翻了所有的题解,发现巨佬写的都是倍增,复杂度是\(O(n\log n\log nw)\)的 ...
- Luogu1084 NOIP2012D2T3 疫情控制 二分答案、搜索、贪心、倍增
题目传送门 题意太长就不给了 发现答案具有单调性(额外的时间不会对答案造成影响),故考虑二分答案. 贪心地想,在二分了一个时间之后,军队尽量往上走更好.所以我们预处理倍增数组,在二分时间之后通过倍增看 ...
- Luogu P1084 疫情控制 | 二分答案 贪心
题目链接 观察题目,答案明显具有单调性. 因为如果用$x$小时能够控制疫情,那么用$(x+1)$小时也一定能控制疫情. 由此想到二分答案,将问题转换为判断用$x$小时是否能控制疫情. 对于那些在$x$ ...
- Luogu 1084 NOIP2012 疫情控制 (二分,贪心,倍增)
Luogu 1084 NOIP2012 疫情控制 (二分,贪心,倍增) Description H 国有 n 个城市,这 n 个城市用 n-1 条双向道路相互连通构成一棵树, 1 号城市是首都, 也是 ...
- [NOIP2012]疫情控制 贪心 二分
题面:[NOIP2012]疫情控制 题解: 大体思路很好想,但是有个细节很难想QAQ 首先要求最大时间最小,这种一般都是二分,于是我们二分一个时间,得到一个log. 然后发现一个军队,越往上走肯定可以 ...
- NOIP2012 疫情控制 题解(LuoguP1084)
NOIP2012 疫情控制 题解(LuoguP1084) 不难发现,如果一个点向上移动一定能控制更多的点,所以可以二分时间,判断是否可行. 但根节点不能不能控制,存在以当前时间可以走到根节点的点,可使 ...
随机推荐
- 《JAVA程序设计》第9周学习总结
1. 本章学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结异常相关内容. 2. 书面作业 1.常用异常 题目5-1 1.1 截图你的提交结果(出现学号) 1.2 自己以前编写的代码中经常出现 ...
- javascript:12种JavaScript MVC框架之比较
Gordon L. Hempton是西雅图的一位黑客和设计师,他花费了几个月的时间研究和比较了12种流行的JavaScript MVC框架,并在博客中总结了每种框架的优缺点,最终的结果是,Ember. ...
- npm run build生成路径问题
vue项目中可以使用npm run build 命令生成静态文件夹dist,开发者可以直接点击dist文件夹下面的index.html问价来访问自己的项目,但是用vue-cli生成的项目,当运行npm ...
- lincode.41 最大子数组
最大子数组 描述 笔记 数据 评测 给定一个整数数组,找到一个具有最大和的子数组,返回其最大和. 注意事项 子数组最少包含一个数 您在真实的面试中是否遇到过这个题? Yes 哪家公司问你的这个题? ...
- 用List传递学生信息
集合在程序开发中经常用到,例如,在业务方法中将学生信息.商品信息等存储到集合中,然后作为方法的返回值返回给调用者,以此传递大量的有序数据. 本实例将使用List集合在方法之间传递学生的信息.实例效果如 ...
- Spring01-IOC
1,新建一个Java Project 导入如下jar包和apache-commons-logging包 2, 在src目录下创建一个beans.xml的配置文件,先加入schema spring-be ...
- 通用技术 : 异步调用 - Ajax技术
Ajax技术概述
- spring cloud+dotnet core搭建微服务架构:服务发现(二)
前言 上篇文章实际上只讲了服务治理中的服务注册,服务与服务之间如何调用呢?传统的方式,服务A调用服务B,那么服务A访问的是服务B的负载均衡地址,通过负载均衡来指向到服务B的真实地址,上篇文章已经说了这 ...
- mysql 存储引擎介绍1
1.1 存储引擎的使用 数据库中的各表均被(在创建表时)指定的存储引擎来处理. 服务器可用的引擎依赖于以下因素: MySQL的版本 服务器在开发时如何被配置 启动选项 为了解当前服务器中有哪些存储引 ...
- Nginx学习——Nginx启动、停止、重启和信号控制以及平滑升级
1.Nginx 启动与停止 (1)启动方式 启动格式:Nginx可执行文件地址 -c Nginx配置文件地址 /etc/local/nginx/sbin/nginx -c /root/dufy/ngi ...