Description:

H 国有 n 个城市,这 n 个城市用 n-1 条双向道路相互连通构成一棵树,1 号城市是首都,也是树中的根节点。

H 国的首都爆发了一种危害性极高的传染病。当局为了控制疫情,不让疫情扩散到边境城市(叶子节点所表示的城市),决定动用军队在一些城市建立检查点,使得从首都到边境城市的每一条路径上都至少有一个检查点,边境城市也可以建立检查点。但特别要注意的是,首都是不能建立检查点的。

现在,在 H 国的一些城市中已经驻扎有军队,且一个城市可以驻扎多个军队。一支军队可以在有道路连接的城市间移动,并在除首都以外的任意一个城市建立检查点,且只能在一个城市建立检查点。一支军队经过一条道路从一个城市移动到另一个城市所需要的时间等于道路的长度(单位:小时)。

请问最少需要多少个小时才能控制疫情。注意:不同的军队可以同时移动。

Input:

第一行一个整数 n,表示城市个数。

接下来的 n-1 行,每行 3 个整数,u、v、w,每两个整数之间用一个空格隔开,表示从城市 u 到城市 v 有一条长为 w 的道路。数据保证输入的是一棵树,且根节点编号为 1。

接下来一行一个整数 m,表示军队个数。

接下来一行 m 个整数,每两个整数之间用一个空格隔开,分别表示这 m 个军队所驻扎的城市的编号。

Output:

共一行,包含一个整数,表示控制疫情所需要的最少时间。如果无法控制疫情则输出-1。

思路:首先二分答案,然后对于每支军队,到根节点的子节点的距离小于mid的全都到根节点的子节点集中,其他军队都尽量往上走,能走到哪就是哪。然后将根节点的子节点上的军队剩余时间排序,剩余时间最小且无法做到去一趟根节点再回来的军队驻守在原来的子节点上,其他军队都到根节点上,然后排序,并将所有没有军队的子节点排序,贪心扫描一遍即可

  1. #include<algorithm>
  2. #include<iostream>
  3. #include<vector>
  4. #include<cstring>
  5. #include<cstdio>
  6. #define ll long long
  7. using namespace std;
  8. const int N = ;
  9. typedef pair<int,int> P;
  10.  
  11. int head[N], now;
  12. struct edges{
  13. int to, next, w;
  14. }edge[N<<];
  15. void add(int u,int v,int w){ edge[++now] = {v, head[u], w}; head[u] = now;}
  16. //dep存储深度,pre存储每个点父节点,e_pre存储每个点的上一条边 dict存储每个点所对应的根节点的子节点
  17. //pos存储军队初始位置 f存储每个根节点的子节点上的病毒能否到达叶子
  18. int n, m, pre[N], pos[N], dict[N], e_pre[N];
  19. ll l, r, tot, dep[N];
  20. bool stop[N], f[N]; //stop指那些无法到达根节点的子节点的军队停留的位置
  21. vector<int> id[N]; //id存储每个根节点的子节点下的军队
  22. vector<P> vec[N]; //该表存储的是每个根节点的子节点上驻扎的军队以及剩余时间
  23. vector<int> A, B; //该表存储的是军队的剩余时间和每个军队到根节点后再到各个子节点的距离
  24.  
  25. int dfs1(int x,int root){ //一趟dfs获取深度,父节点等信息
  26. if(id[x].size()){
  27. for(int i = ; i < id[x].size(); i++)
  28. dict[id[x][i]] = root;
  29. }
  30. for(int i = head[x]; i; i = edge[i].next){
  31. int v = edge[i].to;
  32. if(v == pre[x]) continue;
  33. pre[v] = x;
  34. e_pre[v] = i;
  35. dep[v] = dep[x] + edge[i].w;
  36. dfs1(v, root);
  37. }
  38. }
  39.  
  40. bool dfs2(int x){
  41. bool flag = ;
  42. if(stop[x]) return ;
  43. for(int i = head[x]; i; i = edge[i].next){
  44. int v = edge[i].to;
  45. if(v == pre[x]) continue;
  46. flag = ;
  47. if(!dfs2(v)) return ;
  48. }
  49. if(!flag) return ;
  50. return ;
  51. }
  52.  
  53. void init(){
  54. A.clear();
  55. B.clear();
  56. for(int i = ; i <= n; i++)
  57. vec[i].clear();
  58. memset(stop,,sizeof(stop));
  59. memset(f,,sizeof(f));
  60. }
  61. void work(int x,int lim){
  62. while(edge[e_pre[x]].w <= lim){
  63. lim -= edge[e_pre[x]].w;
  64. x = pre[x];
  65. }
  66. stop[x] = ;
  67. }
  68. bool cmp(P x, P y){ return x.second < y.second; }
  69. bool che(int lim){
  70. init();
  71. for(int i = ; i <= m; i++){
  72. int p = pos[i];
  73. if(dep[p] - dep[dict[i]] > lim){
  74. work(p, lim); continue; //暴力向上走 把军队驻扎到离根节点最近的位置
  75. }
  76. vec[dict[i]].push_back(P(i, lim - (dep[p] - dep[dict[i]])));
  77. }
  78. for(int i = head[]; i; i = edge[i].next){ //判断根节点的每个子节点是否有病毒传播到叶子节点
  79. f[edge[i].to] = dfs2(edge[i].to);
  80. }
  81. for(int i = head[]; i; i = edge[i].next){
  82. int v = edge[i].to;
  83. bool flag = ;
  84. if(vec[v].empty()) if(!f[v]){ //如果该节点上没有军队只能靠其他军队救济
  85. B.push_back(edge[i].w);
  86. continue;
  87. }
  88. sort(vec[v].begin(), vec[v].end(), cmp);//将每个点排序之后贪心地将剩余时间最短的军队驻扎在原地
  89. int tmp = vec[v][].second; //取出剩余时间最少的点
  90. if(tmp - * edge[i].w < && !f[v]) flag = ; //该节点已经被管制
  91. else A.push_back(tmp - edge[i].w);
  92. for(int j = ; j < vec[v].size(); j++){
  93. int x = vec[v][j].first, t = vec[v][j].second;//将子节点上的军队全都调及到根节点
  94. A.push_back(t - edge[i].w);
  95. }
  96. if(!flag && !f[v])
  97. B.push_back(edge[i].w);
  98. }
  99. sort(A.begin(), A.end()); // 贪心扫描 剩余时间最少的军队去最近的子节点
  100. sort(B.begin(), B.end());
  101. int s = ;
  102. for(int i = ; i < A.size(); i++){
  103. if(s == B.size()) break;
  104. if(A[i] >= B[s]) s++;
  105. }
  106. if(s == B.size()) return ;
  107. else return ;
  108. }
  109. int main(){
  110. // freopen("testdata.in","r",stdin);
  111. scanf("%d",&n);
  112. int x, y, z;
  113. for(int i = ; i < n; i++){
  114. scanf("%d%d%d",&x, &y, &z);
  115. add(x, y, z); add(y, x, z);
  116. tot += z;
  117. }
  118. scanf("%d",&m);
  119. for(int i = ; i <= m; i++)
  120. scanf("%d",&pos[i]), id[pos[i]].push_back(i);
  121. for(int i = head[]; i; i = edge[i].next){
  122. dep[edge[i].to] = edge[i].w;
  123. pre[edge[i].to] = , e_pre[edge[i].to] = i;
  124. dfs1(edge[i].to, edge[i].to);
  125. }
  126. r = tot;
  127. ll ans = 1e15;
  128. while(l <= r){
  129. ll mid = l + r >> ;
  130. if(che(mid)) ans = mid, r = mid - ;
  131. else l = mid + ;
  132. }
  133. if(ans == 1e15) puts("-1");
  134. else printf("%lld\n",ans);
  135. return ;
  136. }

NOIP2012 洛谷P1084 疫情控制的更多相关文章

  1. 洛谷P1084 疫情控制(NOIP2012)(二分答案,贪心,树形DP)

    洛谷题目传送门 费了几个小时杠掉此题,如果不是那水水的数据的话,跟列队的难度真的是有得一比... 话说蒟蒻仔细翻了所有的题解,发现巨佬写的都是倍增,复杂度是\(O(n\log n\log nw)\)的 ...

  2. [NOIP2012] 提高组 洛谷P1084 疫情控制

    题目描述 H 国有 n 个城市,这 n 个城市用 n-1 条双向道路相互连通构成一棵树,1 号城市是首都, 也是树中的根节点. H 国的首都爆发了一种危害性极高的传染病.当局为了控制疫情,不让疫情扩散 ...

  3. 洛谷P1084 疫情控制 [noip2012] 贪心+树论+二分答案 (还有个小bugQAQ

    正解:贪心+倍增+二分答案 解题报告: 正好想做noip的题目然后又想落实学长之前讲的题?于是就找上了这题 其实之前做过,70,然后实在细节太多太复杂就不了了之,现在再看一遍感觉又一脸懵了... 从标 ...

  4. 洛谷 P1084 疫情控制 —— 二分+码力

    题目:https://www.luogu.org/problemnew/show/P1084 5个月前曾经写过一次,某个上学日的深夜,精疲力竭后只有区区10分,从此没管... #include< ...

  5. 2018.09.26洛谷P1084 疫情控制(二分+倍增)

    传送门 好题啊. 题目要求的最大值最小,看到这里自然想到要二分答案. 关键在于怎么检验. 显然对于每个点向根走比向叶节点更优. 因此我们二分答案之后,用倍增将每个点都向上跳到跳不动为止. 这时我们ch ...

  6. 洛谷P1084 疫情控制(贪心+倍增)

    这个题以前写过一遍,现在再来写,感觉以前感觉特别不好写的细节现在好些多了,还是有进步吧. 这个题的核心思想就是贪心+二分.因为要求最小时间,直接来求问题将会变得十分麻烦,但是如果转换为二分答案来判断可 ...

  7. 洛谷P1084 疫情控制

    题目 细节比较多的二分+跟LCA倍增差不多的思想 首先有这样一个贪心思路,深度越低的检查点越好,而最长时间和深度具有单调性,即给定时间越长,每个军队能向更浅的地方放置检查点.因此可以考虑二分时间,然后 ...

  8. 洛谷P1084 [NOIP2012提高组Day2T3]疫情控制

    P1084 疫情控制 题目描述 H 国有 n 个城市,这 n 个城市用 n-1 条双向道路相互连通构成一棵树,1 号城市是首都,也是树中的根节点. H 国的首都爆发了一种危害性极高的传染病.当局为了控 ...

  9. NOIP2012 D2 T3 疫情控制 洛谷P1084

    题目链接:https://www.luogu.org/problemnew/show/P1084 算法:倍增,二分答案,贪心 + 瞎搞.. 背景:上学长的数论课啥也听不懂,于是前去提高组找安慰.不巧碰 ...

随机推荐

  1. laravel 中出现SQLSTATE[HY000] [2002] 如何解决?

    在日常开发中总是难免遇到各式各样的错误,还有许多错误常常是重复出现的 以下是报错信息! SQLSTATE[HY000] [2002] ������ӷ���һ��ʱ���û���ȷ�

  2. CacheManager源码分析

    计算rdd的某个分区是从RDD的iterator()方法开始的,我们从这个方法进入 然后我们进入getOrCompute()方法中看看是如何进行读取数据或计算的 getOrElseUpdate()方方 ...

  3. Python基础02

    6.变量定义的规则: # 变量,只能由 字母 数字 下划线 特例:不能用数字开头 Python关键字,也不能使用 'and', 'as', 'assert', 'break', 'class', 'c ...

  4. git将本地项目上传到远程仓库

    1.cd mygit 打开项目文件夹 2.git init 初始化git 3.git remote add origin xxx(远程仓库地址)  添加远程库   git remote -v 查看远程 ...

  5. C# 控制台应用程序输出颜色字体

    最佳解决方案的代码: static void Main(string[] args) { Console.ForegroundColor = ConsoleColor.Green; Console.W ...

  6. linux安装oracle远程客户端

    文章参考:http://blog.csdn.net/caomiao2006/article/details/11901123 感谢博友分享O(∩_∩)O~ 安装oracle 远程客户端(一般情况下本地 ...

  7. 「日常训练」「小专题·图论」 Cow Contest (1-3)

    题意 分析 问题是要看出来这是个floyd闭包问题.我没看出来- - 分析之后补充. 代码 // Origin: // Theme: Graph Theory (Basic) // Date: 080 ...

  8. 在Kotlin上怎样用Mockito2 mock final 类(KAD 23)

    作者:Antonio Leiva 时间:Mar 2, 2017 原文链接:https://antonioleiva.com/mockito-2-kotlin/ 如我们在前面文章中谈到的,Kotlin最 ...

  9. 【CodeForces】9B-Running Student

    目录 Question Description Input Output Solution 解法1 Question Description 小明在公交车始发站上车,他应该在哪个站点下车才能最快到达学 ...

  10. LeetCode 92 ——反转链表 II

    1. 题目 2. 解答 我们需要先找到第 m 个结点及其上一个结点,然后将从 m 到 n 的结点进行反转,最后依次将 m 到 n 反转后的结点和 n 之后的结点放入原链表中即可. 从前往后依次遍历 m ...