NOIP2012疫情控制(二分答案+树上贪心)
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疫情控制(二分答案+树上贪心)的更多相关文章
- luogu1084 [NOIp2012]疫情控制 (二分答案+倍增+dfs序)
先二分出一个时间,把每个军队倍增往上跳到不能再跳 然后如果它能到1号点,就记下来它跳到1号点后剩余的时间:如果不能,就让它就地扎根,记一记它覆盖了哪些叶节点(我在这里用了dfs序+差分,其实直接dfs ...
- 洛谷P1084 疫情控制(NOIP2012)(二分答案,贪心,树形DP)
洛谷题目传送门 费了几个小时杠掉此题,如果不是那水水的数据的话,跟列队的难度真的是有得一比... 话说蒟蒻仔细翻了所有的题解,发现巨佬写的都是倍增,复杂度是\(O(n\log n\log nw)\)的 ...
- Luogu1084 NOIP2012D2T3 疫情控制 二分答案、搜索、贪心、倍增
题目传送门 题意太长就不给了 发现答案具有单调性(额外的时间不会对答案造成影响),故考虑二分答案. 贪心地想,在二分了一个时间之后,军队尽量往上走更好.所以我们预处理倍增数组,在二分时间之后通过倍增看 ...
- Luogu P1084 疫情控制 | 二分答案 贪心
题目链接 观察题目,答案明显具有单调性. 因为如果用$x$小时能够控制疫情,那么用$(x+1)$小时也一定能控制疫情. 由此想到二分答案,将问题转换为判断用$x$小时是否能控制疫情. 对于那些在$x$ ...
- Luogu 1084 NOIP2012 疫情控制 (二分,贪心,倍增)
Luogu 1084 NOIP2012 疫情控制 (二分,贪心,倍增) Description H 国有 n 个城市,这 n 个城市用 n-1 条双向道路相互连通构成一棵树, 1 号城市是首都, 也是 ...
- [NOIP2012]疫情控制 贪心 二分
题面:[NOIP2012]疫情控制 题解: 大体思路很好想,但是有个细节很难想QAQ 首先要求最大时间最小,这种一般都是二分,于是我们二分一个时间,得到一个log. 然后发现一个军队,越往上走肯定可以 ...
- NOIP2012 疫情控制 题解(LuoguP1084)
NOIP2012 疫情控制 题解(LuoguP1084) 不难发现,如果一个点向上移动一定能控制更多的点,所以可以二分时间,判断是否可行. 但根节点不能不能控制,存在以当前时间可以走到根节点的点,可使 ...
- NOIP2012疫情控制(二分答案+倍增+贪心)
Description H国有n个城市,这n个城市用n-1条双向道路相互连通构成一棵树,1号城市是首都,也是树中的根节点. H国的首都爆发了一种危害性极高的传染病.当局为了控制疫情,不让疫情扩散到边境 ...
- [NOIP2012]疫情控制(二分答案+倍增+贪心)
Description H国有n个城市,这n个城市用n-1条双向道路相互连通构成一棵树,1号城市是首都,也是树中的根节点. H国的首都爆发了一种危害性极高的传染病.当局为了控制疫情,不让疫情扩散到边境 ...
随机推荐
- 1 Servlet 简介
1 Servlet是sun公司提供的一门用于开发动态web资源的技术.用户若用Java技术开发一个动态web资源或者网页,需要完成以下2个步骤:① 编写一个Java类,实现servlet接口② 把开发 ...
- 转《vue引入第三方js库》
一.绝对路径直接引入,全局可用 二.绝对路径直接引入,配置后,import 引入后再使用 三.webpack中配置 alias,import 引入后再使用 四.webpack 中配置 plugins, ...
- mysql逻辑架构
逻辑架构图 MySQL有点与众不同,它的逻辑架构可以在多种不同的场景中应用并发挥良好的作用.主要体现在存储引擎的架构上,插件式的存储引擎架构将查询处理和其他的系统任务以及数据的存储提取相分离.这种架构 ...
- python学习笔记(10)--组合数据类型(序列类型)
序列是具有先后关系的一组数据,是一维元素向量,元素类型可以不同,类似数学元素序列,元素间由序号引导,通过下标访问序列的特定元素.序列类型是一个基类类型,字符串类型,元祖类型,列表类型都属于序列类型. ...
- 不使用DataContext直接将ViewModels绑定到ItemsControl控件
在常规的MVVM设计模式中,都是通过DataContext将ViewModels的一个对象绑定到View的DataContext中,从而完成相应地绑定,在本文中我们将通过另外的一种思路来将ViewMo ...
- Slave_SQL_Running:No的两种解决办法
进入slave服务器,运行: mysql> show slave status\G ....... Relay_Log_File: localhost-relay-bin. Relay_Log_ ...
- 记一次tomcat7.0版本启动项目失败问题
测试项目在tomcat7中启动失败,报错如下: @794314bc3 Error during job execution (jobs.Bootstrap) Oops: VerifyError ~ p ...
- 有时候做JQ动画,鼠标经过,它会不停自己抖动不停,解决方法(此处,是兼容IE ,当鼠标经过,遮罩层从下移到上边的JQ动画效果)
<style> .x_sdbb { margin: 60px 0 40px 0; } .x_title2{ background: url(../images/hdb_img17.png) ...
- sql查询(转)
http://www.51testing.com/html/41/n-4421541.html 1 负向条件查询(例如:!=.not in.not exists)都是不能使用索引,少用 可以使用:se ...
- DELPHI中MDI子窗口的关闭和打开
DELPHI中MDI子窗口的关闭 和打开 Delphi中MDI子窗口的关闭方式默认为缩小而不是关闭,所以当你单击子窗口右上角的关闭按钮时会 发觉该子窗口只是最小化,而不是你预期的那样被 ...