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) 不难发现,如果一个点向上移动一定能控制更多的点,所以可以二分时间,判断是否可行. 但根节点不能不能控制,存在以当前时间可以走到根节点的点,可使 ...
随机推荐
- 201521123109《java程序设计》第一周学习总结
1.本章学习总结 java是我这学期学习的一门新的编程语言,个人觉得java还是很深奥的,对于一门新的计算机语言,就像打开了一扇新世界的大门,有许多东西需要不断学习不断探索,除了上课认真听讲,平时还要 ...
- 201521123112《Java程序设计》第13周学习总结
1. 本周学习总结 协议的概念是网络中为了通信而建立的规则,常用的应用层协议有http,ftp等. 测试计算机之间的网络是否连通可以使用ping命令. 可以使用IP+端口号的方法来确定数据包是发给哪个 ...
- js的原型
在讲js的原型之前,必须先了解下Object和Function. Object和Function都作为JS的自带函数,Object继承自己,Funtion继承自己,Object和Function互相是 ...
- [01] Servlet是什么
1.Servlet是什么 Servlet(Server Applet),全称Java Servlet,是用Java编写的服务器端程序.其主要功能在于交互式地浏览和修改数据,生成动态Web内容. 1.1 ...
- Exception in thread "main" org.hibernate.TransientObjectException: object references an unsaved tran
今天在使用一对多,多对一保存数据的时候出现了这个错误 Hibernate错误: Exception in thread "main" org.hibernate.Transient ...
- JSP页面格式化数字或时间 基于jstl的
jsp页面格式化数字或时间 转载自: http://blog.csdn.net/hakunamatata2008/archive/2011/01/21/6156203.aspx Tags fmt:re ...
- 嵌入系统squashfs挂载常见问题总结
由于squahsfs的一些优点,嵌入系统常常直接使用squashfs作为initrd挂载到/dev/ram,作为rootfs.这里对常见的一些问题进行一些分析. 1. kernel启动出现错误 RAM ...
- Node.js 异步异闻录
本文首发在个人博客:http://muyunyun.cn/posts/7b9fdc87/ 提到 Node.js, 我们脑海就会浮现异步.非阻塞.单线程等关键词,进一步我们还会想到 buffer.模块机 ...
- 插入排序-python实现
def insert_sort(arr): for j in range(1,len(arr)): #从list第二个元素开始 key=arr[j] ...
- 逆向实用干货分享,Hook技术第一讲,之Hook Windows API
逆向实用干货分享,Hook技术第一讲,之Hook Windows API 作者:IBinary出处:http://www.cnblogs.com/iBinary/版权所有,欢迎保留原文链接进行转载:) ...