【NOIP2012】 疫情控制

标签: 倍增 贪心 二分答案 NOIP


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。

Sample Input

4

1 2 1

1 3 2

3 4 3

2

2 2

Sample Output

3

Hint

样例说明:

第一支军队在 2 号点设立检查点,第二支军队从 2 号点移动到 3 号点设立检查点,所需 时间为 3 个小时。

【数据范围】

保证军队不会驻扎在首都。

对于 20%的数据,2≤ n≤ 10;

对于 40%的数据,2 ≤n≤50,0<w <10^5;

对于 60%的数据,2 ≤ n≤1000,0<w <10^6;

对于 80%的数据,2 ≤ n≤10,000;

对于 100%的数据,2≤m≤n≤50,000,0<w <10^9


题意

大概意思就是给你n个军队(在不同的城市),你要移动他们到节点上(非根节点)来隔断根节点与每个叶子节点,求移动军队时间的最小值(两个不同的军队可以同时移动)。


题解

  • 首先,移动军队的时间肯定是越多越好,肯定是满足单调性的,我们很容易想到用二分答案来做。
  • 当我们二分答案x之后,我们应该思考军队往哪里走更好,显然是要往上走的,因为每往上走,就能覆盖更大的子树。
  • 对于往上走,我们分两种情况讨论
    1. 如果该军队没有到达根节点,那么我们不用管他,直接让他在这个节点。
    2. 如果该军队到了根节点,那么我们就可以把这个军队往下走一步,来覆盖其他节点。
  • 我们只要把军队还剩下的移动距离和每被覆盖的深度为2的点分别排序,然后扫一遍就行了。
  • 真的这么简单吗?显然不是。如果这么做的话,你会发现样例都过不了。
  • 因为即使某个军队到了根节点,他可能不如只到根节点之前的那个点优秀(因为他可能回不去了),那么我们只需要把回不去的军队弄回去就行了。
  • 对于这个结论其实很好证明:假设该军队为A,他之前的那个点为lst(A),现在他不回去,而选择另外一个点b,去他之前的那个点的军队为B,那么val (A)<val(B),就不如A回去,B再到另外的点。

Code

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<queue>
#include<stack>
#include<set>
#include<map>
using namespace std;
#define ll long long
#define REP(i,a,b) for(int i=(a),_end_=(b);i<=_end_;i++)
#define DREP(i,a,b) for(int i=(a),_end_=(b);i>=_end_;i--)
#define EREP(i,a) for(int i=start[(a)];i;i=e[i].next)
inline int read()
{
int sum=0,p=1;char ch=getchar();
while(!(('0'<=ch && ch<='9') || ch=='-'))ch=getchar();
if(ch=='-')p=-1,ch=getchar();
while('0'<=ch && ch<='9')sum=sum*10+ch-48,ch=getchar();
return sum*p;
} const int maxn=5e5+20; struct node {
int v,next,w;
};
node e[maxn*2];
int n,m;
int start[maxn],cnt; void addedge(int u,int v,int w)
{
e[++cnt]={v,start[u],w};
start[u]=cnt;
} int p[maxn][17],pw[maxn][17],deep[maxn],vis[maxn],st[maxn]; void dfs(int u,int fa)
{
deep[u]=deep[fa]+1;p[u][0]=fa;
EREP(i,u)
{
int v=e[i].v;
if(v==fa)continue;
pw[v][0]=e[i].w;
dfs(v,u);
} } int Sum=0; void init()
{
n=read();
REP(i,1,n-1)
{
int u=read(),v=read(),w=read();
addedge(u,v,w);Sum+=w;
addedge(v,u,w);
}
dfs(1,0);
for(int j=1;(1<<j)<=n;j++)
{
REP(i,1,n)
p[i][j]=p[p[i][j-1]][j-1],pw[i][j]=pw[i][j-1]+pw[p[i][j-1]][j-1];
}
m=read();
REP(i,1,m)st[i]=read();
} bool dfs1(int u,int fa)
{
if(vis[u])return true;
bool flag=false;
EREP(i,u)
{
int v=e[i].v;
if(v==fa)continue;
flag=true;
if(!dfs1(v,u))return false;
}
vis[u]=flag;
return flag;
} struct army {
int use,val,bel,nxt;
};
army a[maxn];
int start_a[maxn];
bool cmp(const army a,const army b)
{
if(a.use==b.use)
return a.val<b.val;
return a.use<b.use;
} bool check(int x)
{
int army_tot=0,army_lst,uncow[maxn]={0},uncow_cnt=0;
memset(a,0,sizeof(a));
memset(vis,0,sizeof(vis));
memset(start_a,0,sizeof(start_a));
REP(i,1,m)
{
int u=st[i],now=0;
DREP(j,16,0)if(p[u][j] && now+pw[u][j]<=x)
{
if(j==0)army_lst=u;
now+=pw[u][j];
u=p[u][j];
}
if(u!=1)vis[u]=1;
else
{
army_tot++;
a[army_tot]={0,x-now,army_lst,start_a[army_lst]};
start_a[army_lst]=army_tot;
}
}
uncow_cnt=0;
EREP(i,1)
{
int v=e[i].v,mn=e[i].w,mn_j;
if(dfs1(v,1))continue;
for(int j=start_a[v];j;j=a[j].nxt)
if(a[j].val<mn)
{
mn=a[j].val;
mn_j=j;
}
if(mn<e[i].w)a[mn_j].use=1;
else uncow[++uncow_cnt]=pw[v][0];
}
sort(uncow,uncow+1+uncow_cnt);
sort(a+1,a+army_tot+1,cmp);
int j=1;
REP(i,1,uncow_cnt)
{
while(a[j].val<uncow[i] && !a[j].use && j<=army_tot)j++;
if(j>army_tot || a[j].use)return false;
j++;
}
return true;
} void doing()
{
int l=1,r=Sum;
while(l<r)
{
int mid=(l+r)>>1;
if(check(mid))r=mid;
else l=mid+1;
}
cout<<l<<endl;
} int main()
{
init();
doing();
return 0;
}

【NOIP2012】 疫情控制的更多相关文章

  1. Luogu 1084 NOIP2012 疫情控制 (二分,贪心,倍增)

    Luogu 1084 NOIP2012 疫情控制 (二分,贪心,倍增) Description H 国有 n 个城市,这 n 个城市用 n-1 条双向道路相互连通构成一棵树, 1 号城市是首都, 也是 ...

  2. [NOIP2012]疫情控制 贪心 二分

    题面:[NOIP2012]疫情控制 题解: 大体思路很好想,但是有个细节很难想QAQ 首先要求最大时间最小,这种一般都是二分,于是我们二分一个时间,得到一个log. 然后发现一个军队,越往上走肯定可以 ...

  3. NOIP2012 疫情控制 题解(LuoguP1084)

    NOIP2012 疫情控制 题解(LuoguP1084) 不难发现,如果一个点向上移动一定能控制更多的点,所以可以二分时间,判断是否可行. 但根节点不能不能控制,存在以当前时间可以走到根节点的点,可使 ...

  4. noip2012 疫情控制

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

  5. NOIP2012疫情控制(二分答案+倍增+贪心)

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

  6. [NOIP2012]疫情控制(二分答案+倍增+贪心)

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

  7. [NOIp2012]疫情控制 题解

    好久没更,强迫自己写一篇. 神 tm 大预言家出的题 注意到如果 \(x\) 小时可以控制住疫情,则 \(\forall x'>x\) 必然也可以控制住疫情,显然答案具有单调性,可以二分答案. ...

  8. NOIP2012疫情控制(二分答案+树上贪心)

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

  9. noip2012疫情控制 题解

    题目大意 给出一棵n个节点的树,根是1,要在除根节点以外的点建立检查点,使得从每条根到叶子的路径上都至少存在一个检查点.检查点由军队来建立.初始军队的位置是给定的,移动军队走一条边需要花费这条边的权值 ...

  10. luogu1084 [NOIp2012]疫情控制 (二分答案+倍增+dfs序)

    先二分出一个时间,把每个军队倍增往上跳到不能再跳 然后如果它能到1号点,就记下来它跳到1号点后剩余的时间:如果不能,就让它就地扎根,记一记它覆盖了哪些叶节点(我在这里用了dfs序+差分,其实直接dfs ...

随机推荐

  1. Java泛型范例

    class Point<T>{ // 此处可以随便写标识符号,T是type的简称 private T var ; // var的类型由T指定,即:由外部指定 public T getVar ...

  2. CCF系列之相反数(201403-1)

    试题名称: 相反数 试题编号: 201403-1时间限制: 1.0s 内存限制: 256.0MB 问题描述 有 N 个非零且各不相同的整数.请你编一个程序求出它们中有多少对相反数(a 和 -a 为一对 ...

  3. PHP获取中英文字符串的首字母

    使用场景:在对地区进行筛选时,我们经常会看到按照英文字母进行筛选定位,起初想着是数据表里存储上地区与首字母关联关系,但是觉得太麻烦,然后就想着根据地区名称来获取首字母,然后对地区进行分组,由此便用到了 ...

  4. C# winform引用com组件,创建AXHOST组件失败解决方案

    解决方法非常简单,请首先关闭你的开发工具然后删除所有*.vshost.exe 的文件. 重新打开visual studio开发工具,重新编译你的程序.

  5. mysql 存在索引但不能使用索引的典型场景

    mysql 演示数据库:http://downloads.mysql.com/docs/sakila-db.zip 以%开头的LIKE查询不能够利用B-tree索引 explain select * ...

  6. 配置python+mod_wsgi+apache 时 在浏览器中访问服务器时报错:Invalid HTTP_HOST header: 'XXXXX'. You may need to add u'XXXXX' to ALLOWED_HOSTS,在setting.py中添加‘*”无效的原因

    配置python+mod_wsgi+apache 时 在浏览器中访问服务器时报错:Invalid HTTP_HOST header: 'XXXXX'. You may need to add u'XX ...

  7. linux_思想

    linux有哪些重要的思想? 1. 做的越多错的越多 2. 纸包不住火 3. 操作重要文件前备份,操作后查看结果 4. 看到命令输出结果,可能命令有个选择直接获得对应值 5. 先定行,再定列

  8. python_鸡兔同笼问题

    鸡兔同笼问题 -- 今有雉兔同笼,上有三十五头,下有九十四足,问雉兔各几何? --鸡和兔在一个笼子里,从上面数,有35个头:从下面数,有94只脚.问笼中各有几只鸡和兔 如何逻辑整理? -- 鸡头和兔子 ...

  9. Java Cookie和Session

    */ .hljs { display: block; overflow-x: auto; padding: 0.5em; color: #333; background: #f8f8f8; } .hl ...

  10. awk完全手册

    awk简介 2. awk命令格式和选项 2.1. awk的语法有两种形式 2.2. 命令选项3. 模式和操作 3.1. 模式 3.2. 操作4. awk的环境变量 5. awk运算符 6. 记录和域  ...