[NOIP2012提高组]疫情控制
题目:洛谷P1084、codevs1218、Vijos P1783。
题目大意:有一棵n个节点的,根为1的带权树和m支军队。每支军队可以在一个点上停下,那么从1开始就不能经过这个点了。现在有m支军队已经在某些点上,移动一支军队到一个相邻的点所花时间等于该条边的边权。军队可同时移动。问至少多少时间才可以使从1开始都到不了任何一个叶子节点(无法满足条件输出-1,根节点不能停军队)。
解题思路:首先,这道题是要求最少的时间,可以二分答案。
然后是一个贪心的思路:让每支军队尽可能向根节点爬。
因为军队越往上,能封住的叶子节点就越多(至少不会减少),那我们在能往上的情况下,尽可能往上。
一支军队如果不能到根节点,就让其在能爬到的最高点停下,并封锁这个节点。
如果能则记录下它剩下的时间和它经过的<根节点的儿子>的编号(即它从哪个儿子过来的)。
然后我们dfs出已经被封锁的节点,如果一个节点的所有儿子都被封锁,则该节点也算被封锁。
之后我们把所有<没被封锁的,根节点的儿子>的编号和到根节点的距离记录下来。
再然后,我们的任务就是把刚刚记录的那些节点,用剩下的能到达根节点的军队去覆盖。
又是贪心,把节点按照到根节点的距离升序排序,把军队按照剩余时间升序排序,然后对于一个节点,用剩余时间最少的,且比这个节点到根节点的距离大(因为要走过去)的军队覆盖。
注意:如果一个军队“经过的<根节点的儿子>”没有被覆盖,则优先覆盖。
最后如果能成功覆盖所有根节点的儿子,则说明答案可行,否则不可行。
对于让军队向上爬的过程,我们可以用倍增的方法进行优化,所以要先预处理。
整理思路:
①预处理倍增。
②二分答案。
对于每个二分的答案:
①让每个军队尽可能向上爬。对于不能到根节点的,让其在能到达的最高节点停下,否则记录下来。对记录数据排序。
②找出所有未被封锁的<根节点的儿子>记录。对记录数据排序。
③用剩余军队覆盖所有未被封锁的根节点的儿子。判断答案是否可行。
以下对时间复杂度分析:
预处理时间复杂度$O(n)$(dfs)+$O(n\log_2 n)$(处理倍增数组)。
判断答案时间复杂度$O(m\log_2 n)$(模拟军队上移)+$O(n)$(找未被封锁的军队)+$O(n\log_2 n+m\log_2 n)$(排序)+$O(n+m)$(贪心,覆盖未被封锁的节点),这些都要乘上二分复杂度$O(\log_2 n)$。
故总时间复杂度$O((n+m)\log^2 n)$。
我不会告诉你我因为一个逗号分隔符两边表达式写反了而调试了一个半小时的
C++ Code:
#include<cstdio>
#include<cctype>
#include<cstring>
#include<algorithm>
using namespace std;
#define N 50005
#define reg register
#define ll long long
int n,m,head[N],cnt,p[N],dep[N],f[N][17],cnta,cntb;
ll g[N][17];
bool vis[N];
struct nd{
ll num;
int d;
bool operator <(const nd& rhs)const{return num<rhs.num;}
}a[N],b[N];
struct edge{
int to,dis,nxt;
}e[N<<1];
inline int readint(){
reg char c=getchar();
for(;!isdigit(c);c=getchar());
reg int d=0;
for(;isdigit(c);c=getchar())
d=(d<<3)+(d<<1)+(c^'0');
return d;
}
void Dfs(int now){//预处理
for(reg int i=head[now];i;i=e[i].nxt)
if(!dep[e[i].to]){
dep[e[i].to]=dep[now]+1;
f[e[i].to][0]=now;
g[e[i].to][0]=e[i].dis;
Dfs(e[i].to);
}
}
void feng(int now){
if(vis[now])return;
vis[now]=true;
reg bool lt=true;
for(reg int i=head[now];i;i=e[i].nxt)
if(dep[now]<dep[e[i].to]){
lt=false;
feng(e[i].to);
vis[now]&=vis[e[i].to];
}
if(lt)vis[now]=false;
}
bool ok(ll k){//判断
reg int x;
reg ll sum;
cnta=cntb=0;
memset(vis,0,sizeof vis);
memset(a,0,sizeof a);
memset(b,0,sizeof b);
for(reg int i=1;i<=m;++i){
x=p[i],sum=0;
for(reg int j=16;j>-1;--j)//让军队爬上来
if(f[x][j]>1&&sum+g[x][j]<=k)
sum+=g[x][j],x=f[x][j];
if(f[x][0]==1&&sum+g[x][0]<=k){
a[++cnta]=(nd){k-sum-g[x][0],x};
}else vis[x]=true;
}
feng(1);//搜索已经被封的节点
if(vis[1])return true;
for(reg int i=head[1];i;i=e[i].nxt)
if(!vis[e[i].to])b[++cntb]=(nd){e[i].dis,e[i].to};
if(cnta<cntb)return false;
reg int zz2=1;
sort(a+1,a+cnta+1);
sort(b+1,b+cntb+1);
for(reg int i=1;i<=cnta&&zz2<=cntb;++i){//判断答案
if(!vis[a[i].d])vis[a[i].d]=true;else{
while(vis[b[zz2].d]&&zz2<=cntb)++zz2;
if(zz2>cntb)return true;
if(a[i].num>=b[zz2].num)vis[b[zz2++].d]=true;
}
while(vis[b[zz2].d]&&zz2<=cntb)++zz2;
}
return zz2>cntb;
}
int main(){
reg ll ans=-1,l=0,r=0;
cnt=0;
memset(head,0,sizeof head);
memset(dep,0,sizeof dep);
memset(f,0,sizeof f);
memset(g,0,sizeof g);
n=readint();
for(reg int i=1;i<n;++i){
reg int u=readint(),v=readint(),t=readint();
r+=t;
e[++cnt]=(edge){v,t,head[u]};
head[u]=cnt;
e[++cnt]=(edge){u,t,head[v]};
head[v]=cnt;
}
m=readint();
for(reg int i=1;i<=m;++i)p[i]=readint();
dep[1]=1;
Dfs(1);
for(reg int j=1;j<17;++j)//预处理++
for(reg int i=1;i<=n;++i){
f[i][j]=f[f[i][j-1]][j-1];
g[i][j]=g[f[i][j-1]][j-1]+g[i][j-1];
}
while(l<=r){//二分
reg ll mid=(l+r)>>1;
if(ok(mid))r=(ans=mid)-1;else
l=mid+1;
}
printf("%lld\n",ans);
return 0;
}
[NOIP2012提高组]疫情控制的更多相关文章
- P1084 [NOIP2012 提高组] 疫情控制 (二分答案、贪心)
因为若一个时间限制满足题意,则所有比它大的时间限制一定都满足题意,因此本题答案具有单调性,可以想到二分答案求解. 本题思路不是很难,但细节和代码实现比较复杂. 见牛人博客:https://www.lu ...
- 刷题总结——疫情控制(NOIP2012提高组)
题目: 题目背景 NOIP2012 提高组 DAY2 试题. 题目描述 H 国有 n 个城市,这 n 个城市用 n-1 条双向道路相互连通构成一棵树,1 号城市是首都,也是树中的根节点. H 国的首都 ...
- GZOJ 1361. 国王游戏【NOIP2012提高组DAY1】
国王游戏[NOIP2012提高组DAY1] Time Limit:1000MS Memory Limit:128000K Description 国王游戏(game.cpp/c/pas) [问题描述] ...
- [NOIP2012] 提高组 洛谷P1084 疫情控制
题目描述 H 国有 n 个城市,这 n 个城市用 n-1 条双向道路相互连通构成一棵树,1 号城市是首都, 也是树中的根节点. H 国的首都爆发了一种危害性极高的传染病.当局为了控制疫情,不让疫情扩散 ...
- 洛谷P1084 [NOIP2012提高组Day2T3]疫情控制
P1084 疫情控制 题目描述 H 国有 n 个城市,这 n 个城市用 n-1 条双向道路相互连通构成一棵树,1 号城市是首都,也是树中的根节点. H 国的首都爆发了一种危害性极高的传染病.当局为了控 ...
- [NOIP2012] day2 T3疫情控制
题目描述 H 国有 n 个城市,这 n 个城市用 n-1 条双向道路相互连通构成一棵树,1 号城市是首都,也是树中的根节点. H 国的首都爆发了一种危害性极高的传染病.当局为了控制疫情,不让疫情扩散到 ...
- [NOIP2012] 提高组 洛谷P1081 开车旅行
题目描述 小 A 和小 B 决定利用假期外出旅行,他们将想去的城市从 1 到 N 编号,且编号较小的 城市在编号较大的城市的西边,已知各个城市的海拔高度互不相同,记城市 i 的海拔高度为 Hi,城市 ...
- 【未完成0.0】Noip2012提高组day2 解题报告
第一次写一套题的解题报告,感觉会比较长.(更新中Loading....):) 题目: 第一题:同余方程 描述 求关于x的同余方程ax ≡ 1 (mod b)的最小正整数解. 格式 输入格式 输入只有一 ...
- NOIP2012 提高组 Day 1
期望得分:100+100+70=270 实际得分:100+50+70=220 T2 没有底 最后剩余时间来不及打高精.思路出现错误 T1 Vigenère 密码 题目描述 16 世纪法国外交家 Bla ...
随机推荐
- Clonezilla制作镜像时报错: errextfsclone.c:bitmap free count err
在检查时选中下面的选项, 如下图: -fsck-src-part Interactively check and repair source file
- 云上建站快速入门:博客、论坛、CMS、电子商务网站统统搞定
现在制作一个网站已经越来越容易了,只要知道清晰的流程之后都是可以很快的建好一个企业或者个人网站的!免费的建站程序很多,下面听哥给你亮出来,建站一般来说分主要有这四步:申请域名.申请虚拟主机.制作网页, ...
- [THUWC2017]在美妙的数学王国中畅游 LCT+泰勒展开+求导
p.s. 复合函数求导时千万不能先带值,再求导. 一定要先将符合函数按照求导的规则展开,再带值. 设 $f(x)=g(h(x))$,则对 $f(x)$ 求导: $f'(x)=h'(x)g'(h(x)) ...
- Airtest ——poco
1. Pymysql(No module named ‘cryptography’) pip install cryptography pip install paramiko 把 cryptogr ...
- Github添加SSHkey
Git详细教程可参考廖雪峰的Git教程 1. 打开 Git Bash,输入cd ~/.ssh——回车(看你是否有了ssh key 密钥,有了就备份): 2. 输入ssh-keygen -t rsa - ...
- HDU 1348 Wall ( 凸包周长 )
链接:传送门 题意:给出二维坐标轴上 n 个点,这 n 个点构成了一个城堡,国王想建一堵墙,城墙与城堡之间的距离总不小于一个数 L ,求城墙的最小长度,答案四舍五入 思路:城墙与城堡直线长度是相等的, ...
- IE6 浏览器常见兼容问题 共23个
1.<!DOCTYPE HTML>文档类型的声明. 产生条件:IE6浏览器,当我们没有书写这个文档声明的时候,会触发IE6浏览器的怪异解析现象: 解决办法:书写文档声明. 2.不同浏览器当 ...
- (转)redis源代码分析 – event library
每个cs程序尤其是高并发的网络服务端程序都有自己的网络异步事件处理库,redis不例外. 事件库仅仅包括ae.c.ae.h,还有3个不同的多路复用(本文仅描述epoll)的wrapper文件,事件库封 ...
- PHP中对hmac_sha1签名算法的实现方法
最近研究网宿云文档API,其中用到了一种叫hmac_sha1的签名算法: HMAC-SHA1: HMAC是哈希运算消息认证码 (Hash-based Message Authentication Co ...
- maven打包可运行的jar包(包含依赖工程)
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/20 ...