[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 ...
随机推荐
- Java中使用MD5加密的简单实现
import java.math.BigInteger; import java.security.MessageDigest; import java.security.NoSuchAlgorith ...
- 分清encodeURIComponent encodeURI 和 escape
encodeURIComponent encodeURI escape 目的:这三个函数的作用都是让一段字符串在所有电脑(所有国家区域语言)上可读. escape对字符串进行处理: encodeURI ...
- BZOJ 5020 [THUWC2017]Drown in the math ocean (LCT+求导)
题目大意: 太长了略 洛谷题面传送门 嗯,数学题 感觉考试要是出这种题我就死翘翘了[逃 不用想都知道要$LCT$维护断边连边,但询问该如何处理呢 利用题目给出的公式 $f(x)=\sum_{i=0}^ ...
- ansible 主机清单 /etc/ansible/hosts
主机清单 [webservers] ansible01 ansible02 ansible03 ansible04 [root@ftp:/root] > ansible webservers - ...
- invalid application of `sizeof' to incomplete type `char[] '
在写代码时,我想用extern来关联一个数组,然后利用sizeof计算数组的大小,代码如下: ... extern char a[]; #define b size=(sizeof(a)/sizeof ...
- Qt之命令行参数
简述 在Qt之进程间通信(QProcess)一节,我们讲解了如何通过QProcess来进行进程间的通信.主要通过启动外部程序,然后通过命令行的方式传递参数. 这里,我们可以通过Qt Creator来设 ...
- POJ 2296 Map Labeler(2-sat)
POJ 2296 Map Labeler 题目链接 题意: 坐标轴上有N个点.要在每一个点上贴一个正方形,这个正方形的横竖边分别和x,y轴平行,而且要使得点要么在正方形的上面那条边的中点,或者在以下那 ...
- android全磁盘加密
android 全磁盘加密 什么是全磁盘加密? 全磁盘加密是使用一个密钥来为android设备上全部的用户数据加密的过程.一旦设备被加密,全部的用户创建的数据都将会在提交的磁盘之前自己主动加密,在读取 ...
- Hibernate的xml方法配置和操作代码
一.gradle中包: compile group: 'org.hibernate', name: 'hibernate-core', version: '5.2.12.Final' compile ...
- HDU 5375 Gray code(2015年多校联合 动态规划)
题目连接 : 传送门 题意: 给定一个长度为的二进制串和一个长度为n的序列a[],我们能够依据这个二进制串得到它的Gray code. Gray code中假设第i项为1的话那么我们就能够得到a[i] ...