题意:

题目描述

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

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

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

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

输入格式

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

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

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

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

输出格式

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

数据范围

洛咕,即官方数据范围:

LOJ:

吐槽:

LOJ这数据……真的天坑我艹

看LOJ数据以为$O(n^2logn)$只有30很虚,结果去看官方数据有60……

然后我$O(nlogn)$的正解不仅要开longlong还被卡常卡成95,在洛咕秒过……

SBLOJ!

题解:

由于军队可以同时移动,所以题目要求的就是使最大值最小,这种最优化问题明显二分答案;

一个结论是军队肯定离根节点越近控制的点越多,即深度越小越优,所以军队选择的策略肯定是向上走;

这样贪心的思路就是让尽量多的军队走到根节点,然后走到那些没有军队的根节点的子节点上,这样子就控制了以那个子节点为根的整个子树;

但是有些军队在时间限制内是走不到根节点的,所以要按照走不走得到根节点分类,如果走不到就留在能走到的最高的点,把这些点设为已被控制,走的到的暂时放在根节点,然后记录这些军队是从根节点的哪个子节点走上来的;

这时可以dfs一遍求出哪些点已经被控制了,注意如果一个点的所有子节点都被控制了那么这个点也算被控制了,然后记录下所有没被控制的根节点的子节点;

按照剩余的时间给所有能到达根节点的军队排序,按照到根节点的距离给没被控制的那些子节点排序,明显剩余时间多军队的去支援到根节点距离远的子节点是最优的;

但是还有个问题,就是有些军队去支援后自己来源的那个子节点反而没有军队去控制;

因此排序时要从小到大,然后优先让每个军队向下回到自己来源的那个子节点(这样做就可以忽略上到根节点又回去的过程,所以时间肯定符合),否则去支援其他子节点,最后判断能否控制所有子节点即可。

这里快速求距离用树上倍增实现。

讲的比较复杂,代码里细节也很多,写的时候要注意。

代码:

(LOJ被卡常95分,不加读入优化90分)

 #include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<queue>
#define inf 10000000000000000
#define eps 1e-9
using namespace std;
typedef long long ll;
struct edge{
int v,w,next;
}a[];
struct node{
ll v;
int id;
friend bool operator <(node a,node b){
return a.v<b.v;
}
}ar[],nd[];
int n,m,u,v,w,tot=,cnt=,_cnt=,arm[],fa[][],head[];
ll ans=-,l,r,sum=,dis[][];
bool isin[];
char buffer[],*hd,*tl;
inline char Getchar(){
if(hd==tl){
int len=fread(buffer,,,stdin);
hd=buffer,tl=hd+len;
if(hd==tl)
return EOF;
}
return *hd++;
}
inline int rd(){
register int x=;
char c;
do c=Getchar();
while(!isdigit(c));
do{
x=(x<<)+(x<<)+(c^);
c=Getchar();
}while(isdigit(c));
return x;
}
void add(int u,int v,int w){
a[++tot].v=v;
a[tot].w=w;
a[tot].next=head[u];
head[u]=tot;
}
void dfs(int u,int ff,int ds){
fa[u][]=ff;
dis[u][]=ds;
for(int i=;i<=;i++){
fa[u][i]=fa[fa[u][i-]][i-];
dis[u][i]=dis[u][i-]+dis[fa[u][i-]][i-];
}
for(int tmp=head[u];tmp!=-;tmp=a[tmp].next){
int v=a[tmp].v;
if(v!=ff){
dfs(v,u,a[tmp].w);
}
}
}
void dfstf(int u,int fa){
bool t1=true,t2=false;
for(int tmp=head[u];tmp!=-;tmp=a[tmp].next){
int v=a[tmp].v;
if(v!=fa){
dfstf(v,u);
t1&=isin[v];
t2=true;
}
}
if(t1&&t2&&u!=)isin[u]=true;
}
bool chk(ll k){
int nw,ret=;
ll d=;
for(int i=;i<=n;i++)isin[i]=false;
cnt=_cnt=;
for(int i=;i<=m;i++){
nw=arm[i];
d=;
for(int j=;j>=;j--){
if(fa[nw][j]&&d+dis[nw][j]<=k){
d+=dis[nw][j];
nw=fa[nw][j];
}
}
if(nw!=)isin[nw]=true;
else{
int vv=arm[i];
for(int j=;j>=;j--){
if(fa[vv][j]>)vv=fa[vv][j];
}
ar[++cnt].v=k-d;
ar[cnt].id=vv;
}
}
dfstf(,);
for(int tmp=head[];tmp!=-;tmp=a[tmp].next){
int v=a[tmp].v;
if(!isin[v]){
nd[++_cnt].v=a[tmp].w;
nd[_cnt].id=v;
}
}
sort(ar+,ar+cnt+);
sort(nd+,nd+_cnt+);
nd[_cnt+].v=inf;
for(int i=;i<=cnt;i++){
if(!isin[ar[i].id])isin[ar[i].id]=true;
else if(ar[i].v>=nd[ret].v)isin[nd[ret].id]=true;
while(isin[nd[ret].id])ret++;
}
return ret>_cnt;
}
int main(){
memset(head,-,sizeof(head));
//scanf("%d",&n);
n=rd();
for(int i=;i<n;i++){
//scanf("%d%d%d",&u,&v,&w);
u=rd(),v=rd(),w=rd();
add(u,v,w);
add(v,u,w);
sum+=w;
}
//scanf("%d",&m);
m=rd();
for(int i=;i<=m;i++)arm[i]=rd();//scanf("%d",&arm[i]);
l=,r=sum;
dfs(,,);
while(l<=r){
ll mid=(l+r)/;
if(chk(mid))ans=mid,r=mid-;
else l=mid+;
}
printf("%lld",ans);
return ;
}

[LOJ2607]【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. unity 模型 材质 贴图 关系;着色器属性

    模型包含 材质(Material),包括 [核心]着色器(Shader) 贴图和其他参数,贴图也算是一种参数 其他,如网格渲染器(Mesh Renderer).动画.坐标 一个材质可以看做为一个Sha ...

  2. 大数乘法 poj2389

    Bull Math Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 14972   Accepted: 7695 Descri ...

  3. linux系统添加环境变量,node.js forever 守护进程添加环境变量

    1.node.js 守护进程组件 forever 安装 npm install forever -g 安装完成后截图: 2.安装完成后在控制台输入 forever 出现 -bash: forever: ...

  4. Mysql字段合并

    现有数据 合并字段显示:利用GROUP_CONCAT(course,":","score") 严格区分大小写!GROUP_CONCAT 复制代码 SELECT ...

  5. 首页 > 所有书 > 操作系统 > Linux >

    http://book.51cto.com/col/1213/list_1213_8.htm linux一些经典教材

  6. javascript-js中技巧集合

    1.值的转换 在JavaScript中,一共有两种类型的值:原始值(primitives)和对象值(objects).原始值有:undefined, null, 布尔值(booleans), 数字(n ...

  7. Java相关知识(一)

    1. 作用域public.protected.private以及不写时的差别? public 表示公有.声明的为公共成员变量和函数成员.在整个类内类外都可使用,对全部用户开放,能够直接进行调用 pri ...

  8. 浅析Mysql InnoDB存储引擎事务原理

    浅析Mysql InnoDB存储引擎事务原理 大神:http://blog.csdn.net/tangkund3218/article/details/47904021

  9. Android之——自己定义TextView

    转载请注明出处:http://blog.csdn.net/l1028386804/article/details/47082241 在这一篇博文中,将向大家介绍怎样以最简单的方式,来自己定义Andro ...

  10. centos下mysql多实例安装3306、3307实例(2014-10-15)

    背景说明       mysql的安装方法有多种,如二进制安装.源代码编译安装.yum安装等.yum安装仅仅能安装mysql 5.1 版本号:源代码安装编译的过程比較长.若没有对源代码进行改动且要求使 ...