6301 疫情控制 0x60「图论」例题

描述

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

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

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

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

输入格式

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

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

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

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

输出格式

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

样例输入

4
1 2 1
1 3 2
3 4 3
2
2 2

样例输出

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。

来源

CCF NOIP2012 D2T3

        </article>

题解

参照evenbao的题解。

细心观察发现 : 此题的答案具有单调性,也就是说,如果p小时能控制疫情,那么q小时也能控制疫情(q > p),因此我们可以二分答案,这是此题的突破口

问题就转化为了检验”Mid小时是否可以控制住疫情“

我们发现,既然要求所有叶子节点得到管辖,那么,军队所在的节点深度越浅,所能管辖的节点数就越多,我们不妨让每支军队都先移动到所能移动的最顶端(不能移动到根节点),具体实现时,我们可以通过倍增预处理每个节点向上2^j条边的边权总和。

此时,我们可以将军队分为两类 :

第一类 : 位于根节点的儿子节点

第二类 : 位于非根节点的儿子节点

对于第二类军队,我们让它保持不动即可,对于第一类军队,我们可以让它管辖自己所在子树的叶子节点,当然,我们也可以让它跨过根节点,管辖其所能到达的(不超过时间限制的),其它子树的叶子节点

这里有一条结论 : 对于一支第一类军队,如果这支军队不能跨过根节点并回到该节点,那么该节点必然由目前停留在这个节点上,且不能跨过根节点并回到该节点的,剩余时间最少的军队所管辖

根据这条结论,我们对于每个尚未被管辖的,根节点的子节点,查找是否有目前在该节点上并不能跨过根节点回到该节点的第一类军队,在这些军队中找剩余时间最少的管辖该节点,并将这支军队删除

对于剩余的第一类军队,我们可以先求出尚未被管辖的,根节点的子节点,然后,将军队按剩余时间 - 到达根节点的时间升序排列,将节点按到根节点的距离升序排列,贪心扫描一遍即可

时间复杂度\(O((n+m)\log n\log SUM)\),SUM为边权和。

#include<bits/stdc++.h>
#define rg register
#define il inline
#define co const
template<class T>il T read(){
rg T data=0,w=1;rg char ch=getchar();
for(;!isdigit(ch);ch=getchar())if(ch=='-') w=-w;
for(;isdigit(ch);ch=getchar()) data=data*10+ch-'0';
return data*w;
}
template<class T>il T read(rg T&x) {return x=read<T>();}
typedef long long ll;
using namespace std; co int N=5e4+1;
int head[N],Edge[N*2],Leng[N*2],Next[N*2],tot;
int n,m,t,a[N],b[N],g[N],fa[N][16],sh[N];
ll c[N],d[N],f[N],dis[N][16],sum;
vector<ll> arv[N];
queue<int> q;
bool v[N],w[N]; void add(int x,int y,int z){
Edge[++tot]=y,Leng[tot]=z,Next[tot]=head[x],head[x]=tot;
}
void bfs(){
v[1]=1;
for(int i=head[1];i;i=Next[i]){
int y=Edge[i];
q.push(y);
v[y]=1;
b[sh[y]=++t]=i;
}
while(q.size()){
int x=q.front();
q.pop();
for(int i=head[x];i;i=Next[i]){
int y=Edge[i];
if(v[y]) continue;
q.push(y);
v[y]=1;
fa[y][0]=x;
dis[y][0]=Leng[i];
for(int j=1;j<16;++j){
fa[y][j]=fa[fa[y][j-1]][j-1];
dis[y][j]=dis[y][j-1]+dis[fa[y][j-1]][j-1];
}
}
}
}
bool dfs(int x){ // check if ok
v[x]=1;
if(!sh[x]&&w[x]) return 1;
bool flag=0; // not leaf
for(int i=head[x];i;i=Next[i]){
int y=Edge[i];
if(v[y]) continue;
flag=1;
if(!dfs(Edge[i])) return 0;
}
return flag;
}
bool work(ll now){
for(int i=1;i<=t;++i) arv[i].clear();
memset(v,0,sizeof v),memset(w,0,sizeof w);
v[1]=1;
for(int i=1;i<=m;++i){
g[i]=a[i],d[i]=0;
for(int j=15;j>=0;--j)
if(fa[g[i]][j]&&d[i]+dis[g[i]][j]<=now)
d[i]+=dis[g[i]][j],g[i]=fa[g[i]][j];
w[g[i]]=1;
int j=sh[g[i]];
if(j){
arv[j].push_back(now-d[i]);
if(arv[j].size()>1&&now-d[i]>arv[j][arv[j].size()-2])
swap(arv[j][arv[j].size()-1],arv[j][arv[j].size()-2]);
}
}
int p=0,q=0;
for(int i=1;i<=t;++i){
if(!dfs(Edge[b[i]])){
if(arv[i].size()&&arv[i][arv[i].size()-1]<2*Leng[b[i]])
arv[i].pop_back();
else f[++q]=Leng[b[i]];
}
for(unsigned j=0;j<arv[i].size();++j)
if(arv[i][j]>=Leng[b[i]])
c[++p]=arv[i][j]-Leng[b[i]];
}
sort(c+1,c+p+1),sort(f+1,f+q+1);
if(p<q) return 0;
for(int i=q,j=p;i;--i,--j)
if(c[j]<f[i]) return 0;
return 1;
}
int main(){
read(n);
for(int i=1,x,y,z;i<n;++i){
read(x),read(y),read(z);
add(x,y,z),add(y,x,z),sum+=z;
}
read(m);
for(int i=1;i<=m;++i) read(a[i]);
bfs();
ll l=0,r=sum+1;
while(l<r){
ll mid=(l+r)>>1;
if(work(mid)) r=mid;
else l=mid+1;
}
if(l>sum) puts("-1");
else printf("%lld\n",l);
return 0;
}

CH6301 疫情控制的更多相关文章

  1. Codevs 1218 疫情控制 2012年NOIP全国联赛提高组

    1218 疫情控制 2012年NOIP全国联赛提高组 时间限制: 2 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题目描述 Description H 国有 n 个城市,这 ...

  2. 【NOIP2012】 疫情控制

    [NOIP2012] 疫情控制 标签: 倍增 贪心 二分答案 NOIP Description H 国有 n 个城市,这 n 个城市用 n-1 条双向道路相互连通构成一棵树, 1 号城市是首都, 也是 ...

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

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

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

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

  5. 疫情控制 blockade

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

  6. codevs1218 疫情控制

    疫情控制(blockade.cpp/c/pas)[问题描述]H 国有 n 个城市,这 n 个城市用 n-1 条双向道路相互连通构成一棵树,1 号城市是首都,也是树中的根节点.H 国的首都爆发了一种危害 ...

  7. 疫情控制 2012年NOIP全国联赛提高组(二分答案+贪心)

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

  8. luoguP1084 疫情控制(题解)(搜索+贪心)

    luoguP1084 疫情控制 题目 #include<iostream> #include<cstdlib> #include<cstdio> #include& ...

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

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

随机推荐

  1. java的特性与优势

    java的特性与优势 简单性 面向对象 可移植性 高性能 分布式 动态性 多线程 安全性 健壮性

  2. appium怎么按下系统按键?如按下返回键、home键等等

    ava_client3.0版本以后使用pressKeyCode方法,之前的版本使用sendKeyEvent方法 1. 返回:driver.pressKeyCode(AndroidKeyCode.BAC ...

  3. [JAVA] maven 阿里云节点 settings.xml

    <?xml version="1.0" encoding="UTF-8"?> <settings xmlns="http://mav ...

  4. 修复一个mysqlbinlog_flashback不支持json格式问题

    修复一个mysqlbinlog_flashback不支持json格式问题 , 有问题可以反馈留言 , 如下盘: 最简单的例子为 python mysqlbinlog_back.py --host=&q ...

  5. Windows常用网络命令(3)

    5.Netstat Netstat命令可以帮助网络管理员了解网络的整体使用情况.它可以显示当前正在活动的网络连接的详细信息,例如显示网络连接.路由表和网络接口信息,可以统计目前总共有哪些网络连接正在运 ...

  6. HDU6608-Fansblog(Miller_Rabbin素数判定,威尔逊定理应用,乘法逆元)

    Problem Description Farmer John keeps a website called ‘FansBlog’ .Everyday , there are many people ...

  7. Java设计模式--代理模式+动态代理+CGLib代理

    静态代理 抽象主题角色:声明真实主题和代理主题的共同接口. 代理主题角色:代理主题内部含有对真实主题的引用,从而在任何时候操作真实主题对象:代理主题提供一个与真实主题相同的接口,以便在任何时候都可以代 ...

  8. [转帖]直击案发现场!TCP 10倍延迟的真相是?

    直击案发现场!TCP 10倍延迟的真相是? http://zhuanlan.51cto.com/art/201911/605268.htm 内核参数调优 非常重要啊. 什么是经验?就是遇到问题,解决问 ...

  9. Java线程的等待与唤醒完整示例代码

    项目结构: 资源类: 输入线程:  输出线程: 测试: 人妖问题发生: 线程安全问题的解决方法: 调用Object的wait()和notify()方法时需注意:必须是锁对象方可调用,否则将抛出无效的监 ...

  10. 通俗易懂的join、left join、right join、full join、cross join

    内连接:列出与连接条件匹配的数据行(join\inner join) 外连接:两表合并,如有不相同的列,另外一个表显示null(left join\right join\full outer join ...