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

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

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

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

Solution

一眼望上去十分不可做,开始%大佬的博客。

发现正解是二分答案。

发现确实有单调性(有单调性一定要二分!!)

首都把整颗树分成了好几个部分。

对于每个军队,在不跳过首都的情况下,越靠上越优,所以我们把没治军队暴力向上跳答案的高度。

但会有跳过的情况。。

跳到首都的军队,不会再跳到别的地方了,我们干脆让它跳到根节点下的那个点。

对于跳过的点,我们记下它在那个部分和它还能跳多远,放到数组里按距离从小到大排序。

遍历这颗子树,求出没有被覆盖完全的子树根,放到数组/堆中从小到大排序。

扫一遍所有军队。

若军队所在子树没有被覆盖,那我就守家(因为这是它最好的选择)。

否则让它去别的子树。

Code

#include<iostream>
#include<cstdio>
#include<queue>
#include<algorithm>
#include<cstring>
#include<vector>
#define N 60009
using namespace std;
int n,head[N],tot,p[N][],deep[N],maxdeep,dep[N],top,m,w[N],tag[N],bu,ans;
bool has[N];
long long d[N][];
struct node{
int id,s;
bool operator < (const node &b)const{
return s>b.s;
}
};
bool cmp(node a,node b){
return a.s<b.s;
}
node ve[N];
priority_queue<node>q;
struct fd{
int n,to,l;
}e[N<<];
inline void add(int u,int v,int l){e[++tot].n=head[u];e[tot].to=v;e[tot].l=l;head[u]=tot;}
int rd(){
int x=;
char c=getchar();
while(!isdigit(c))c=getchar();
while(isdigit(c)){
x=(x<<)+(x<<)+(c^);
c=getchar();
}
return x;
}
void dfs(int u,int fa){
p[u][]=fa;d[u][]=deep[u]-deep[fa];maxdeep=max(maxdeep,deep[u]);
for(int i=;(<<i)<=dep[u];++i)
p[u][i]=p[p[u][i-]][i-],d[u][i]=deep[u]-deep[p[u][i]];
for(int i=head[u];i;i=e[i].n)if(e[i].to!=fa){
int v=e[i].to;
deep[v]=deep[u]+e[i].l;
dep[v]=dep[u]+;
dfs(v,u);
}
}
bool dfs3(int u,int fa){
if(has[u])return ;
bool tt=;
for(int i=head[u];i;i=e[i].n)if(e[i].to!=fa){
if(dfs3(e[i].to,u))return ;
tt=;
}
if(!tt)return ;
return ;
}
bool check(int pos){
top=;
while(q.size())q.pop();
memset(has,,sizeof(has));
for(int i=;i<=m;++i){
int now=w[i],D=pos;
for(int j=;j>=;--j)
if(D>=d[now][j]&&p[now][j])D-=d[now][j],now=p[now][j];
if(now==&&!D)has[tag[w[i]]]=;
if(now==&&D)ve[++top]=node{tag[w[i]],D};
if(now!=)has[now]=;
}
sort(ve+,ve+top+,cmp);
// for(int i=1;i<=top;++i)cout<<ve[i].s<<" "<<ve[i].id<<endl;
// cout<<top<<endl;
for(int i=head[];i;i=e[i].n){
int v=e[i].to;
if(dfs3(v,))q.push(node{v,e[i].l});
else has[v]=;
}
for(int i=;i<=top;++i){
if(q.empty())return true;
if(!has[ve[i].id])has[ve[i].id]=;
else{
node x=q.top();
while(q.size()&&has[x.id]){//care
q.pop();x=q.top();
}
if(has[x.id])return ;
if(x.s<=ve[i].s){
q.pop();
has[x.id]=;//care
}
}
}
while(q.size()&&has[q.top().id])q.pop();
if(q.empty())return true;
else return false;
}
void dfs2(int u,int fa){
tag[u]=bu;for(int i=head[u];i;i=e[i].n)if(e[i].to!=fa)dfs2(e[i].to,u);
}
int main(){
n=rd(); int u,v,ww;
for(int i=;i<n;++i)u=rd(),v=rd(),ww=rd(),add(u,v,ww),add(v,u,ww);
m=rd();
for(int i=;i<=m;++i)w[i]=rd();
dfs(,);
for(int i=head[];i;i=e[i].n){
bu=e[i].to;
dfs2(bu,);
}
int l=,r=maxdeep*;//care
ans=-;
while(l<=r){
int mid=(l+r)>>;
if(check(mid)){
ans=mid;
r=mid-;
}
else l=mid+;
}
printf("%d\n",ans);
return ;
}

NOIP2012疫情控制(二分答案+树上贪心)的更多相关文章

  1. luogu1084 [NOIp2012]疫情控制 (二分答案+倍增+dfs序)

    先二分出一个时间,把每个军队倍增往上跳到不能再跳 然后如果它能到1号点,就记下来它跳到1号点后剩余的时间:如果不能,就让它就地扎根,记一记它覆盖了哪些叶节点(我在这里用了dfs序+差分,其实直接dfs ...

  2. 洛谷P1084 疫情控制(NOIP2012)(二分答案,贪心,树形DP)

    洛谷题目传送门 费了几个小时杠掉此题,如果不是那水水的数据的话,跟列队的难度真的是有得一比... 话说蒟蒻仔细翻了所有的题解,发现巨佬写的都是倍增,复杂度是\(O(n\log n\log nw)\)的 ...

  3. Luogu1084 NOIP2012D2T3 疫情控制 二分答案、搜索、贪心、倍增

    题目传送门 题意太长就不给了 发现答案具有单调性(额外的时间不会对答案造成影响),故考虑二分答案. 贪心地想,在二分了一个时间之后,军队尽量往上走更好.所以我们预处理倍增数组,在二分时间之后通过倍增看 ...

  4. Luogu P1084 疫情控制 | 二分答案 贪心

    题目链接 观察题目,答案明显具有单调性. 因为如果用$x$小时能够控制疫情,那么用$(x+1)$小时也一定能控制疫情. 由此想到二分答案,将问题转换为判断用$x$小时是否能控制疫情. 对于那些在$x$ ...

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

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

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

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

  7. NOIP2012 疫情控制 题解(LuoguP1084)

    NOIP2012 疫情控制 题解(LuoguP1084) 不难发现,如果一个点向上移动一定能控制更多的点,所以可以二分时间,判断是否可行. 但根节点不能不能控制,存在以当前时间可以走到根节点的点,可使 ...

  8. NOIP2012疫情控制(二分答案+倍增+贪心)

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

  9. [NOIP2012]疫情控制(二分答案+倍增+贪心)

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

随机推荐

  1. TCP 握手和挥手图解(有限状态机)

    1.引言 TCP 这段看过好几遍,老是记不住,没办法找工作涉及到网络编程这块,各种问 TCP .今天好好整理一下握手和挥手过程.献给跟我一样忙碌,找工作的童鞋,欢迎大神批评指正. 2.TCP 的连接建 ...

  2. 上古神器之Vim编辑器

    在Linux操作环境下进行文本的编辑少不了编辑器vi ,vim,nona... 一. 修改颜色方案 有时候,使用vim打开一个文件,竟然是蓝色的,辨识度相当的差,这个时候,我们可以调整 一下颜色的搭配 ...

  3. 图片转字符画 【学习ing】

    1.创建ascii.py 2. 下面是 ascii.py 的完整代码: from PIL import Image import argparse #命令行输入参数处理 parser = argpar ...

  4. MySQL设计SQL语句优化规范

    原文:http://bbs.landingbj.com/t-0-240751-1.html 1. 使用mysql explain 对sql执行效率进行检测 ,explain显示了mysql如何使用索引 ...

  5. 区块链教程(二):比特币、区块链、以太坊、Hyperledger的关系

    不知道大家喜不喜欢音乐! 朋克音乐:诞生于七十年代中期,一种源于六十年代车库摇滚和前朋克摇滚的简单摇滚乐.它由一个简单悦耳的主旋律和三个和弦组成,经过演变,朋克已经逐渐脱离摇滚,成为一种独立的音乐,朋 ...

  6. java中去除字符串(String)中的换行字符(\r \n \t)

    例1: public class Test { public static void main(String[] args) { String s = "'sds gdasda" ...

  7. Hadoop2.0 Namenode HA实现方案

    Hadoop2.0 Namenode HA实现方案介绍及汇总 基于社区最新release的Hadoop2.2.0版本,调研了hadoop HA方面的内容.hadoop2.0主要的新特性(Hadoop2 ...

  8. 使用IWMS的网站打开显示“未能加载文件或程序集”,解决方案

    首先,会出现这样的问题原因是: 1.应用程序集里面有些事互相引用的,所以 问题有多种情况,第一.这个应用程序集出问题了: 2.它所依赖的那个程序集出问题了: 3.在项目生成的时候,代码里面有逻辑错误: ...

  9. git 提交顺序

    0. git branch   # 查看自己是哪个分支:先确定自己现在是哪个分支 1. git fetch    # 将远程主机的更新,全部取回本地.如果只想取回特定分支的更新,可以指定分支名:git ...

  10. MySQL的FIND_IN_SET()函数

    今天在做项目时,看到了一个从没见过的MySQL函数——FIND_IN_SET(),顿时就产生了浓郁的兴趣,然后就搜了搜,翻了翻. 语法:FIND_IN_SET(str,strlist) 定义: 1. ...