题意:

题目描述

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. iOS开发-测量APP启动耗时

    冷启动 冷启动就是App被kill掉以后一切从头开始启动的过程. 热启动 当用户按下home键的时候,iOS的App并不会马上被kill掉,还会继续存活若干时间.理想情况下,用户点击App的图标再次回 ...

  2. iOSUI显示思想

    两级显示机制: 1.cpu: 2.GPU: 和操作系统的多级缓存机制有点类似.

  3. ZBrush中关于标记的特殊情况

    在ZBrush®中使用Marker标记调控板来记忆物体属性,因此能在任何时间回到标记并使用它给其他物体或改变物体作为参考点,在使用Marker标记调控板时回出现很多特殊情况,本文小编就这些特殊情况做一 ...

  4. 洛谷1613 跑路 倍增 + Floyd

    首先,我们一定要认识到本题中的最短时间所对应的道路不一定是在起点到终点的最短路.例如,起点到终点的最短路为 151515 ,那么对 151515 进行二进制拆分的话是 111111111111 ,这时 ...

  5. 实验楼—Mysql—查找最爱学的课程

    转载:https://www.shiyanlou.com/challenges/2651 背景 从上节题目构建的课程数据库中提取每个用户最爱学的课程数据. 右边桌面是实验楼的服务器,服务器中的 MyS ...

  6. python之类与对象的属性

    类相关的知识 在python2中的区分: 经典类: class School: pass 新式类: class School(object): pass 在python3中以上两种均为新式类 属性: ...

  7. 实现js保留小数点后N位的代码

    在JS中,一般实现保留小数点后N位的话,都是利用toFixed函数 <script language="javascript"> document.write(&quo ...

  8. Linux网络编程(一):一个简单的socket程序

    服务器: /* *tcp_server.c */ #include <stdio.h> #include <sys/socket.h> #include <netinet ...

  9. PHP实现的毫秒定时器,同时解决进程不重复堆积

    定时器任务,在WEB应用比较常见,如何使用PHP实现定时器任务,大致有两种方案:1)使用Crontab命令,写一个shell脚本,在脚本中调用PHP文件,然后定期执行该脚本:2)配合使用ignore_ ...

  10. 决策树(Decision Trees)

    简介 决策树是一个预测模型,通过坐标数据进行多次分割,找出分界线,绘制决策树. 在机器学习中,决策树学习算法就是根据数据,使用计算机算法自动找出决策边界. 每一次分割代表一次决策,多次决策而形成决策树 ...