题意:

题目描述

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. C++面向对象的设计思想——小结

    1 对象的概念 面向对象(Object Oriented Analysis Design,OOAD)的思想把整个世界看成是由具有某种特征行为功能的基本单元——对象构成的.OOAD把一个对象的特征称为属 ...

  2. addEventListener()与removeEventListener(),追加事件和删除追加事件

    addEventListener()与removeEventListener()用于追加事件和删除追加.所有的DOM节点中都包含这两种方法,并且它们都接受3个参数:要处理的事件名.作为事件处理程序的函 ...

  3. 路飞学城Python-Day50

    05-运算符 常用运算符 算数运算符 赋值运算符 比较运算符 逻辑运算符         // 赋值运算符          var money = prompt('请输入金额');          ...

  4. 【XSY2689】王子 - 网络流

    复活!qwq 题目来源:2018冬令营模拟测试赛(九) 题意: [背景描述]     不是所有王子都会遇见自己的中关村,主公,公主. 从前有个王子姓王,王王子遇到了一位美丽的公主,她的名字当然是公公主 ...

  5. 一、frp官方中文文档

    frp 是一个可用于内网穿透的高性能的反向代理应用,支持 tcp, udp, http, https 协议. 目录 frp 的作用 开发状态 架构 使用示例 通过 ssh 访问公司内网机器 通过自定义 ...

  6. centos7最小化安装图形界面

    1.安装X Window System命令 yum groupinstall "X Window System" 选择y直接安装就可以了 2.安装图形界面软件 GNOME yum ...

  7. LeetCode 11. Container With Most Water 单调队列

    题意 Given n non-negative integers a1, a2, ..., an, where each represents a point at coordinate (i, ai ...

  8. Sybase数据库工具DbVisualizer乱码问题

    使用DbVisualizer来操作sybase数据库的时候,会出现乱码问题,中文变成  '口口'. 解决的方法例如以下: 将这三个字体都改成 "宋体"  或者改成 "PM ...

  9. android sudio 执行的中文是乱码解决方式

    1.File-->Setings-->查找file encodings 例如以下图 2.将 IDE Encoding .Project Encoding.Default encoding ...

  10. BZOJ2154: Crash的数字表格 & BZOJ2693: jzptab

    [传送门:BZOJ2154&BZOJ2693] 简要题意: 给出n,m,求$\sum_{i=1}^{n}\sum_{j=1}^{m}LCM(i,j)$ 题解: 莫比乌斯反演(因为BZOJ269 ...