[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 ...
随机推荐
- PHP内置SOAP扩展客户端的使用例子
SOAP已经是属于OUT范畴的技术了,不过因为历史原因,时不时还是会用到它,以前都是用NuSOAP,现在准备试试PHP内置的SOAP扩展.由于文本只打算说说客户端的用法,所以得先找一些能直接用的服务端 ...
- df与du查看磁盘空间使用不一致的解决方法
近一段时间,某台服务器的磁盘空间使用不太正常,与其他的服务器相比,严重超出磁盘空间使用 使用df与du相关命令查看,具体结果如下: du -hFilesystem Size Used A ...
- JAVA 重载方法,参数为NULL时,调用的处理 (精确性原则)
引子:大家可以思考一下下面程序的输出结果 public class TestNull { public void show(String a){ System.out.println("St ...
- 【【henuacm2016级暑期训练】动态规划专题 J】Red-Green Towers
[链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] 显然最多1000行的样子. 从上到小做dp 设f[i][j]为前i行,使用了j个红色方块的方案数. f[1][r] = 1;如果r& ...
- mysql_5.6.24_winx64 安装
1.将zip压缩文件放在一个文件夹中 2.将路劲加入path环境变量 3.注册系统服务 在C:\windows下建立一个ini文件 1 2 3 4 5 6 7 8 9 10 11 12 [client ...
- Tarjan缩点【模板】
#include <algorithm> #include <cstdio> #include <map> using namespace std; ); map& ...
- Tarjan强联通分量【模板】
#include <algorithm> #include <cstdio> using namespace std; ); int n,m,v,u; int edgesum, ...
- 极路由4pro安装java(Jamvm 2.0.0 + gnu classpath 0.9.8)
首先试了gnu classpath 0.9.9,编译不过后来改成0.9.8 编译环境 OS: 64位 Ubuntu 16.04 LTS(vmware虚拟机) SDK: 用之前讲过的官方SDKmtmip ...
- POJ 3270
黑书上的经典题了.我说说解这个题的巧妙的地方吧. 首先,竟然和置换联系起来了.因为其实一个交换即至少可以使其中一个元素到达指定位置了.和循环置换联合起来,使得一个循环内的数可以一步到达指定位置,很巧妙 ...
- flex 通过htmlservices链接moss的rest(rest 的get post方式)
一:flex debug(调试)--trace() --moss导入 flex学习:1.flex出现不能使用trace调试语句的问题,控制台无信息输出.这个问题不须要改动安装文件的參量. 仅仅须要下载 ...