【noip2012】疫情控制
题意:
给出一颗n个节点有边权的树 和m个军队所在的位置 军队从某节点移动到相邻节点要花费边长度的时间 求最少要多少时间使得根节点(编号为1)到每个叶子的路径上最少有一支军队(根节点不能有军队)
题解:
我们可以二分答案 那么问题就转换为 在t的时间内军队能否控所有点
显然一支军队在到根节点之前 如果能继续向上走 那么这支军队能控制的点就会更多
维护bo[i]表示 从该点到所有该点子树的叶子节点路径上是否都有军队
对于每个不能走到根节点的军队 就让他尽量向上走 直到不能走为止 将该点的bo值赋为1 然后可以用拓扑算出bo数组
这样 根节点的所有儿子中bo为1的点就不用管 而剩下的点就需要派能走到根节点的军队到这些点控制
于是问题转换为 有n0个点需要被控制 且控制该点需要Li的时间 还有m0支军队 每支军队有ti的时间 求这m0支军队是否能控制这n0个点
这原本这样将L和t分别排序 贪心用两个指针一个个扫就行了
但是要注意的是如果军队j就是从i点走到首都的 那么该军队不论有多少剩余时间都能控制该点(去年noip考试的时候好像就是没想到这点)
这个问题我们只要做一个小转换就行了 如果i点有军队从该点到达首都 那么用minarm[i]记下这些军队中剩余时间最少的是谁 当指针扫到i时先判断minarm[i]是否被用过了 如果没有 那么用minarm[i]来控制i 否则再在j指针上找军队
证明:如果minarm[i]没被使用 那么t[j]>=t[minarm[i]] 所以在i点如果用minarm[i]则能省下一个剩余时间更多的军队 对于之后可能用到minarm[i]的点完全可以用j点代替
代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
using std::sort;
const int N=;
struct inli{
int next,data,lon;
inli(const int a=,const int b=,const int c=):
next(a),data(b),lon(c){}
}line[N*];
struct info{
int t,s;
info(const int a=,const int b=):
t(a),s(b){}
}ar[N],ci[N];
inline bool cmp(info a,info b){ return a.s>b.s; }
int n,m,na,nc,fat[N],ti[N],gra[N],dis[N],arm[N],nl,son[N],mint[N],add,boo[N];
int max(int x,int y){ return x>y ? x : y; }
void dfs(int t){
int res=-,bo1=,bo2=;
for (int i=son[t];i;i=line[i].next)
if (line[i].data!=fat[t]){
int ne=line[i].data;
dfs(ne);
if (ti[ne]==-) bo2=;
if (ti[ne]-line[i].lon>=) bo1=;
res=max(res,ti[ne]-line[i].lon);
}
if (t!= && line[son[t]].next){
if (bo1) ti[t]=max(ti[t],res);
else if (bo2) ti[t]=max(ti[t],-);
else ti[t]=max(ti[t],);
}
}
void maketi(int t){
for (int i=;i<=m;i++)
if (dis[arm[i]]>=t) ti[arm[i]]=t;
dfs();
}
void makear(int t){
na=;
for (int i=;i<=m;i++)
if (dis[arm[i]]<t) ar[++na]=info(gra[arm[i]],t-dis[arm[i]]);
sort(ar+,ar+na+,cmp);
for (int i=;i<=na;i++){
int x=ar[i].t;
if (mint[x]==) mint[x]=i;
else if (ar[mint[x]].s>ar[i].s) mint[x]=i;
}
}
void makeci(){
nc=;
for (int i=son[];i;i=line[i].next)
if (ti[line[i].data]==-) ci[++nc]=info(line[i].data,line[i].lon);
sort(ci+,ci+nc+,cmp);
}
bool work(){
if (na<nc) return ;
memset(boo,,sizeof(boo));
for (int i=,j=;i<=nc;i++)
if (!boo[mint[ci[i].t]] && mint[ci[i].t]) boo[mint[ci[i].t]]=;
else{
while (boo[j] && j<=na) ++j;
if (j>na) return ;
if (ar[j].s<ci[i].s) return ;
boo[j++]=;
}
return ;
}
bool check(int t){
memset(ti,-,sizeof(ti));
memset(mint,,sizeof(mint));
maketi(t);
makear(t);
makeci();
return work();
}
int getans(){
int l=-,r=,mid;
while (l+<r){
mid=(l+r)/;
if (check(mid)) r=mid;
else l=mid;
}
return r;
}
void makefat(int t){
for (int i=son[t];i;i=line[i].next)
if (line[i].data!=fat[t]){
int ne=line[i].data;
if (t==) gra[ne]=ne;
else gra[ne]=gra[t];
fat[ne]=t;
dis[ne]=dis[t]+line[i].lon;
makefat(ne);
}
}
int main(){
freopen("blockade.in","r",stdin);
freopen("blockade.out","w",stdout);
scanf("%d",&n);
for (int x,y,z,i=;i<n;i++){
scanf("%d%d%d",&x,&y,&z);
line[++nl]=inli(son[x],y,z),son[x]=nl;
line[++nl]=inli(son[y],x,z),son[y]=nl;
if (x== || y==) ++add;
}
makefat();
scanf("%d",&m);
if (m<add){
printf("-1");
return ;
}
for (int i=;i<=m;i++) scanf("%d",&arm[i]);
sort(arm+,arm+m+);
printf("%d",getans());
fclose(stdin);
fclose(stdout);
}
【noip2012】疫情控制的更多相关文章
- Luogu 1084 NOIP2012 疫情控制 (二分,贪心,倍增)
Luogu 1084 NOIP2012 疫情控制 (二分,贪心,倍增) Description H 国有 n 个城市,这 n 个城市用 n-1 条双向道路相互连通构成一棵树, 1 号城市是首都, 也是 ...
- [NOIP2012]疫情控制 贪心 二分
题面:[NOIP2012]疫情控制 题解: 大体思路很好想,但是有个细节很难想QAQ 首先要求最大时间最小,这种一般都是二分,于是我们二分一个时间,得到一个log. 然后发现一个军队,越往上走肯定可以 ...
- NOIP2012 疫情控制 题解(LuoguP1084)
NOIP2012 疫情控制 题解(LuoguP1084) 不难发现,如果一个点向上移动一定能控制更多的点,所以可以二分时间,判断是否可行. 但根节点不能不能控制,存在以当前时间可以走到根节点的点,可使 ...
- noip2012 疫情控制
[问题描述] H国有n个城市,这n个城市用n-1条双向道路相互连通构成一棵树,1号城市是首都,也是树中的根节点. H国的首都爆发了一种危害性极高的传染病.当局为了控制疫情,不让疫情扩散到边境城市(叶子 ...
- NOIP2012疫情控制(二分答案+倍增+贪心)
Description H国有n个城市,这n个城市用n-1条双向道路相互连通构成一棵树,1号城市是首都,也是树中的根节点. H国的首都爆发了一种危害性极高的传染病.当局为了控制疫情,不让疫情扩散到边境 ...
- [NOIP2012]疫情控制(二分答案+倍增+贪心)
Description H国有n个城市,这n个城市用n-1条双向道路相互连通构成一棵树,1号城市是首都,也是树中的根节点. H国的首都爆发了一种危害性极高的传染病.当局为了控制疫情,不让疫情扩散到边境 ...
- [NOIp2012]疫情控制 题解
好久没更,强迫自己写一篇. 神 tm 大预言家出的题 注意到如果 \(x\) 小时可以控制住疫情,则 \(\forall x'>x\) 必然也可以控制住疫情,显然答案具有单调性,可以二分答案. ...
- NOIP2012疫情控制(二分答案+树上贪心)
H 国有n个城市,这 n个城市用n-1条双向道路相互连通构成一棵树,1号城市是首都,也是树中的根节点. H国的首都爆发了一种危害性极高的传染病.当局为了控制疫情,不让疫情扩散到边境城市(叶子节点所表示 ...
- noip2012疫情控制 题解
题目大意 给出一棵n个节点的树,根是1,要在除根节点以外的点建立检查点,使得从每条根到叶子的路径上都至少存在一个检查点.检查点由军队来建立.初始军队的位置是给定的,移动军队走一条边需要花费这条边的权值 ...
- luogu1084 [NOIp2012]疫情控制 (二分答案+倍增+dfs序)
先二分出一个时间,把每个军队倍增往上跳到不能再跳 然后如果它能到1号点,就记下来它跳到1号点后剩余的时间:如果不能,就让它就地扎根,记一记它覆盖了哪些叶节点(我在这里用了dfs序+差分,其实直接dfs ...
随机推荐
- hdu 4101
比赛的时候先是受以前一个圣神海的题目 用了两遍DFS 第一遍标记出围墙 第二遍求围墙外和每块围墙降为1所需的攻击次数 结果爆栈 改为BFS后AC DFS的加了一句这个 #pragma comme ...
- 深入浅出 ES6:ES6 与 Babel / Broccoli 的联用
深入浅出 ES6指的是添加在 ECMASript 标准第六版中的 JavaScript 编程语言的新特性,简称为 ES6. 虽然 ES6 刚刚到来,但是人们已经开始谈论 ES7 了,它未来的样子,以及 ...
- 【leetcode】4Sum(middle)
Given an array S of n integers, are there elements a, b, c, and d in S such that a + b + c + d = tar ...
- nginx负载均衡和反向代理有什么区别
近在研究nginx的负载均衡和反向代理,先看下这两个简单的配置吧! 负载均衡 worker_processes 1; events { worker_connections 1024; } http{ ...
- 删除appcompat_v7会出很多错误
创建工程的时候会出现appcompat_v7这个文件夹 手贱删除后,发现出错了 说明test项目是依赖于appcompat_v7包的,所以这个appcompat_v7包是不能被删除的. appcomp ...
- Google Code Style
Google开源项目的代码遵循的规范,见这,C++, OC. PS: vim的配色编辑用户主目录下的.vimrc即可.
- MySQL 普通索引、唯一索引和主索引
1.普通索引 普通索引(由关键字KEY或INDEX定义的索引)的唯一任务是加快对数据的访问速度.因此,应该只为那些最经常出现在查询条件(WHEREcolumn=)或排序条件(ORDERBYcolumn ...
- PHP使用Mysql事务实例解析
<?php //数据库连接 $conn = mysql_connect('localhost', 'root', ''); mysql_select_db('test', $conn); mys ...
- I2C I2S SPDIF
I2C总线 大多数是用于电视机等家用电器的(显卡与显示器之间的通讯也是)I2S: I2S(Inter—IC Sound)总线, 又称 集成电路内置音频总线,是飞利浦公司为数字音频设备之间的音频数据传输 ...
- Java之数组array和集合list、set、map
之前一直分不清楚java中的array,list.同时对set,map,list的用法彻底迷糊,直到看到了这篇文章,讲解的很清楚. 世间上本来没有集合,(只有数组参考C语言)但有人想要,所以有了集合 ...