洛谷P1084 疫情控制
细节比较多的二分+跟LCA倍增差不多的思想
首先有这样一个贪心思路,深度越低的检查点越好,而最长时间和深度具有单调性,即给定时间越长,每个军队能向更浅的地方放置检查点。因此可以考虑二分时间,然后判断军队是否可以放置在控制疫情的地方。
但是有的军队需要先满足自己当前所在的节点,然后此节点如果有多个军队,其他军队跳到1节点,再跳到1节点的其他子树,这里又有一个贪心策略,就是每个军队跳到1的剩余时间:二分的当前时间减去到1节点的距离越大,就要跳到1的另一个子树里据1最远的点,这样才能更好地使得控制疫情。
#include <bits/stdc++.h>
#define N 1001001
using namespace std;
struct edg {
int to, nex, len;
}e[N];
struct tem {
int id, len;
}a[N], b[N];
int n, m, cnt, lin[N], vis[N], vis2[N], army[N], dep[N], fa[N][19], dis[N][19];//fa[i][j]表示军队向上跳j次所到达的位置,dis表示此时所用的时间。
//vis表示该点包括的叶子节点是否被完全覆盖
bool cmp(tem x, tem y)
{
return x.len < y.len;
}
inline void add(int f, int t, int l)
{
e[++cnt].len = l;
e[cnt].to = t;
e[cnt].nex = lin[f];
lin[f] = cnt;
}
void dfs(int now, int f)
{
fa[now][0] = f;
dep[now] = dep[f] + 1;
for (int i = lin[now]; i; i = e[i].nex)
{
int to = e[i].to;
if (to == f) continue;
dis[to][0] = e[i].len;
dfs(to, now);
}
}
void bF(int now)//判断该点的所有叶子节点是否全都被覆盖
{
int b1 = 1, b2 = 0;
if (vis[now]) return;
for (int i = lin[now]; i; i = e[i].nex)
{
int to = e[i].to;
if (to == fa[now][0])
continue;
b2 = 1;
bF(to);
if (!vis[to])
b1 = 0;
}
if (b1 && b2 && now != 1)
vis[now] = 1;
}
bool check(int mid)//使每个军队都尽可能的往上跳,直到距离比mid大才停止。
{
memset(vis, 0, sizeof(vis));
memset(vis2, 0, sizeof(vis2));
int tnt1 = 0, tnt2 = 0;
for (int i = 1; i <= m; i++)
{
int u = army[i], dn = 0;
for (int j = 18; j >= 0; j--) if (dn + dis[u][j] <= mid && fa[u][j] != 0) dn += dis[u][j], u = fa[u][j];
if (u != 1)//如果此点不为1说明此点可以被覆盖。
vis[u] = 1;
else
{
a[++tnt1].len = mid - dn;
int u2 = army[i];
for (int j = 18; j >= 0; j--) if (fa[u2][j] > 1) u2 = fa[u2][j];
a[tnt1].id = u2;
}
}
bF(1);
for (int i = lin[1]; i; i = e[i].nex)//枚举深度为2的点
{
int to = e[i].to;
if (vis[to]) continue;//找到没有完全覆盖完的to; 然后加以覆盖。 选一定要选深度最浅的,所以选择深度为2的,这样选择一定是最优解。
b[++tnt2].id = to, b[tnt2].len = e[i].len;
}
sort(a + 1, a + 1 + tnt1, cmp);//a的len是剩余的时间
sort(b + 1, b + 1 + tnt2, cmp);//b的len是需要的时间, 他们的时间相加
int j = 1;
for (int i = 1; i <= tnt1; i++)
{
if (!vis[a[i].id]) vis[a[i].id] = 1;//先把此点给覆盖了。
else if (a[i].len >= b[j].len) vis[b[j].id] = 1;
while (vis[b[j].id] && j <= tnt2) j++;
}
if (j > tnt2)
return 1;
else
return 0;
}
inline void init()
{
scanf("%d", &n);
for (int i = 1, u, v, w; i < n; i++)
{
scanf("%d%d%d", &u, &v, &w);
add(u, v, w);
add(v, u, w);
}
scanf("%d", &m);
for (int i = 1; i <= m; i++)
scanf("%d", &army[i]);
dfs(1, 0);
for (int j = 1; j <= 18; j++)
for (int i = 1; i <= n; i++)
{
fa[i][j] = fa[fa[i][j - 1]][j - 1];
dis[i][j] = dis[i][j - 1] + dis[fa[i][j - 1]][j - 1];//dis[i][j]是i向上跳j步所走的路径长度,此叶子节点的意思是最深的节点
}
}
int main()
{
init();
int ans, l = 0, r = 70000000;
while (l <= r)
{
int mid = (l + r) >> 1;
if (check(mid))
ans = mid, r = mid - 1;
else
l = mid + 1;
}
printf("%d", ans);
return 0;
}
洛谷P1084 疫情控制的更多相关文章
- 洛谷P1084 疫情控制(NOIP2012)(二分答案,贪心,树形DP)
洛谷题目传送门 费了几个小时杠掉此题,如果不是那水水的数据的话,跟列队的难度真的是有得一比... 话说蒟蒻仔细翻了所有的题解,发现巨佬写的都是倍增,复杂度是\(O(n\log n\log nw)\)的 ...
- [NOIP2012] 提高组 洛谷P1084 疫情控制
题目描述 H 国有 n 个城市,这 n 个城市用 n-1 条双向道路相互连通构成一棵树,1 号城市是首都, 也是树中的根节点. H 国的首都爆发了一种危害性极高的传染病.当局为了控制疫情,不让疫情扩散 ...
- NOIP2012 洛谷P1084 疫情控制
Description: H 国有 n 个城市,这 n 个城市用 n-1 条双向道路相互连通构成一棵树,1 号城市是首都,也是树中的根节点. H 国的首都爆发了一种危害性极高的传染病.当局为了控制疫情 ...
- 洛谷 P1084 疫情控制 —— 二分+码力
题目:https://www.luogu.org/problemnew/show/P1084 5个月前曾经写过一次,某个上学日的深夜,精疲力竭后只有区区10分,从此没管... #include< ...
- 洛谷P1084 疫情控制 [noip2012] 贪心+树论+二分答案 (还有个小bugQAQ
正解:贪心+倍增+二分答案 解题报告: 正好想做noip的题目然后又想落实学长之前讲的题?于是就找上了这题 其实之前做过,70,然后实在细节太多太复杂就不了了之,现在再看一遍感觉又一脸懵了... 从标 ...
- 2018.09.26洛谷P1084 疫情控制(二分+倍增)
传送门 好题啊. 题目要求的最大值最小,看到这里自然想到要二分答案. 关键在于怎么检验. 显然对于每个点向根走比向叶节点更优. 因此我们二分答案之后,用倍增将每个点都向上跳到跳不动为止. 这时我们ch ...
- 洛谷P1084 疫情控制(贪心+倍增)
这个题以前写过一遍,现在再来写,感觉以前感觉特别不好写的细节现在好些多了,还是有进步吧. 这个题的核心思想就是贪心+二分.因为要求最小时间,直接来求问题将会变得十分麻烦,但是如果转换为二分答案来判断可 ...
- 洛谷P1084 [NOIP2012提高组Day2T3]疫情控制
P1084 疫情控制 题目描述 H 国有 n 个城市,这 n 个城市用 n-1 条双向道路相互连通构成一棵树,1 号城市是首都,也是树中的根节点. H 国的首都爆发了一种危害性极高的传染病.当局为了控 ...
- NOIP2012 D2 T3 疫情控制 洛谷P1084
题目链接:https://www.luogu.org/problemnew/show/P1084 算法:倍增,二分答案,贪心 + 瞎搞.. 背景:上学长的数论课啥也听不懂,于是前去提高组找安慰.不巧碰 ...
随机推荐
- jq动画插件,自制基于vue的圆形时钟
首先附上jq插件库,里面的东西太炫了,建议学前端的可以看看学习下:http://www.jq22.com/ 里面有个“超个性动画版本的个人简历”,通过屏幕上不断打印内容,改变相应样式来实现动画简历,我 ...
- 用lambda表达式写左联查询的示例
需要完成的查询逻辑:A表内联B表,B表左联C表,A表左联D表,并且 C表的TotalCount>23,D表的ClassHour>8,最后查出A表的Id,代码如下: IQueryable&l ...
- mvc_第一遍_业务逻辑层和模型
常用的动态网页对象: 之前我们提到了,使用request对象可以获得和用户请求相关的一系列信息.这一节,我们来看看另外两个常用对象的常规用途. response对象:用于向客户回应.最常用的用法类似于 ...
- Mybatis 原理分析
对于入门程序的流程分析 使用过程 读配置文件 读取配置文件时绝对路径和相对路径(web工程部署后没有src路径)都有一定问题,实际开发中一般有两种方法 使用类加载器,它只能读取类路径的配置文件 使用S ...
- vim巧妙用法
1. 块复制 按ctrl+v键,编辑框最下方将出现"可视 块"字样 使用方向键移动光标,选择矩形区域内的文字 y 键复制文本: d 键剪切文本:p 键粘贴文本 按shift+v键, ...
- Unity手游汉化笔记③:UABE替换BMFont
总的笔记:https://www.cnblogs.com/guobaoxu/p/12055930.html 目录 一.Demo 二.分析思路 三.替换 四.总结 五.补充 工具: Unity版本:20 ...
- Unity编辑器扩展中,使用Unity自带的GUIStyle
在进行编辑器扩展时,创建组件的方法一般都会提供GUIStyle参数,可以让我们自定义样式.修改背景图,字体大小,颜色等等. 比如,创建Button组件的方法:public static bool Bu ...
- vue 子组件 $emit方法 调用父组件方法
$emit方法 父组件 <template> <div> <child @callFather="activeSon"></child&g ...
- docker的小技巧记录(如果使用了更多会继续添加)
docker小技巧 复制本地sql脚本到docker容器mysql中进行使用 # 找到容器 docker ps # 复制文件 cp ./xxx.sql container-id:/tmp/ # 进入容 ...
- 10 分钟上手 Vim,常用命令大盘点
传闻有 180 万的程序员不知道如何退出 Vim 编辑器,真的有这么困难吗?下面给大家整理了一份 Vim 常用命令,让你 10 分钟快速上手 Vim,溜得飞起! 以下命令请在普通模式执行 1.移动光标 ...