题意:

题目描述

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. 腾讯测试工程师:你以为会打LOL就能做测试了?

    周日参加完公司团建,回家路上拼到一个IT界的老司机,他和几个朋友组件团队承接开发项目,知道我是做测试的,问了我一个问题: “你们大公司的测试都做什么?” “测试应该不好模仿吧?” 刚开始我也不清楚他的 ...

  2. python3 django动态分页引发的list切片下标越界问题

    起先是扒了一个包,动态分页的,但这个包分页之前要加载全部的数据,我这东西后台是个爬虫,不一定浏览的完所以这么做有点浪费资源,于是我改造了一下. # :param obj_count: 获得 条目总数# ...

  3. 纯css实现宽度自适应,高度与宽度成比例

    html: <div></div> css div{ width: 33.33%; box-sizing: border-box; float: left; position: ...

  4. Ibatis在运行期得到可执行到sql

    环境:oracle-11g ,ibatis-2.0 ,java-1.7 最近因为有个需要是在程序中得到ibatis到sql字符串,即通过以下的ibatis配置得到sql语句 <select id ...

  5. failed to push some refs to 'git@github.com:RocsSun/mytest.git

    Git推送到GitHub仓库失败 使用Git将文件推送至GitHub的远程仓库时,报错failed to push some refs to 'git@github.com:RocsSun/mytes ...

  6. [BZOJ1322]Destroying The Graph

    题目大意:有一张有向图,对于每个点,有两种操作:1. 删掉它的所有入边2. 删掉它的所有出边对每个点的每个操作均有不同的价值.求使得图上没有边的最小价值.解题思路:考虑把点拆成入点和出点,然后就是二分 ...

  7. [HDU1160]FatMouse's Speed

    题目大意:读入一些数(每行读入$w[i],s[i]$为一组数),要求找到一个最长的序列,使得符合$w[m[1]] < w[m[2]] < ... < w[m[n]]$且$s[m[1] ...

  8. BZOJ 2141 排队 (三维偏序CDQ+树状数组)

    题目大意:略 洛谷传送门 和 [CQOI2015]动态逆序对 这道题一样的思路 一开始的序列视为$n$次插入操作 把每次交换操作看成四次操作,删除$x$,删除$y$,加入$x$,加入$y$ 把每次操作 ...

  9. ansible shell模块

    [root@ftp:/root] > ansible ansible01 -u root -k -m shell -a 'hostname' SSH password: ansible01 | ...

  10. AsyncTask 简要介绍

    当Android的UI线程超过5s未响应时,系统会引发ANR(Application Not Responding)异常,所以一般不在UI线程中执行耗时任务.一般是在其他线程中处理耗时任务,然后及时更 ...