题目:洛谷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提高组]疫情控制的更多相关文章

  1. P1084 [NOIP2012 提高组] 疫情控制 (二分答案、贪心)

    因为若一个时间限制满足题意,则所有比它大的时间限制一定都满足题意,因此本题答案具有单调性,可以想到二分答案求解. 本题思路不是很难,但细节和代码实现比较复杂. 见牛人博客:https://www.lu ...

  2. 刷题总结——疫情控制(NOIP2012提高组)

    题目: 题目背景 NOIP2012 提高组 DAY2 试题. 题目描述 H 国有 n 个城市,这 n 个城市用 n-1 条双向道路相互连通构成一棵树,1 号城市是首都,也是树中的根节点. H 国的首都 ...

  3. GZOJ 1361. 国王游戏【NOIP2012提高组DAY1】

    国王游戏[NOIP2012提高组DAY1] Time Limit:1000MS Memory Limit:128000K Description 国王游戏(game.cpp/c/pas) [问题描述] ...

  4. [NOIP2012] 提高组 洛谷P1084 疫情控制

    题目描述 H 国有 n 个城市,这 n 个城市用 n-1 条双向道路相互连通构成一棵树,1 号城市是首都, 也是树中的根节点. H 国的首都爆发了一种危害性极高的传染病.当局为了控制疫情,不让疫情扩散 ...

  5. 洛谷P1084 [NOIP2012提高组Day2T3]疫情控制

    P1084 疫情控制 题目描述 H 国有 n 个城市,这 n 个城市用 n-1 条双向道路相互连通构成一棵树,1 号城市是首都,也是树中的根节点. H 国的首都爆发了一种危害性极高的传染病.当局为了控 ...

  6. [NOIP2012] day2 T3疫情控制

    题目描述 H 国有 n 个城市,这 n 个城市用 n-1 条双向道路相互连通构成一棵树,1 号城市是首都,也是树中的根节点. H 国的首都爆发了一种危害性极高的传染病.当局为了控制疫情,不让疫情扩散到 ...

  7. [NOIP2012] 提高组 洛谷P1081 开车旅行

    题目描述 小 A 和小 B 决定利用假期外出旅行,他们将想去的城市从 1 到 N 编号,且编号较小的 城市在编号较大的城市的西边,已知各个城市的海拔高度互不相同,记城市 i 的海拔高度为 Hi,城市 ...

  8. 【未完成0.0】Noip2012提高组day2 解题报告

    第一次写一套题的解题报告,感觉会比较长.(更新中Loading....):) 题目: 第一题:同余方程 描述 求关于x的同余方程ax ≡ 1 (mod b)的最小正整数解. 格式 输入格式 输入只有一 ...

  9. NOIP2012 提高组 Day 1

    期望得分:100+100+70=270 实际得分:100+50+70=220 T2 没有底 最后剩余时间来不及打高精.思路出现错误 T1 Vigenère 密码 题目描述 16 世纪法国外交家 Bla ...

随机推荐

  1. Xcode 下“ did not have any applicable content ”分析及解决

    问题的产生 a.新建项目时选的iPhone b.为了做成图片启动,按照惯例去掉了LaunchStoryboard的引用,建了个LaunchImage的资源,属性里随便勾了一个,找了张匹配的图拖了过去 ...

  2. C++_String_类字符串操作(转)

    从百度文库找的,挺详细的,跟大家分享一下. 标红的是我觉得用的比较多,并且大家不太熟悉的. string类的构造函数: string(const char *s);     //用c字符串s初始化 s ...

  3. 一个完整的Flexbox指南(转载)

    本文由大漠根据Chris Coyier的<A Complete Guide to Flexbox>所译,整个译文带有我们自己的理解与思想,如果译得不好或不对之处还请同行朋友指点.如需转载此 ...

  4. Pyhton学习——Day46

    # 数据库:存储数据的仓库# 数据库更多的是安全.备份# 客户端取服务端的数据实际都是从服务端的内存中抓取数据# 数据库管理系统软件# 数据库管理系统(Database Management Syst ...

  5. 04 SqlServer

    数据库的注释 –(两个横线) 主键表 外键表 主键,组合主键 SqlServer 使用附加 权限 主文件mdf 日志文件ldf 数据类型 char varchar nchar nvarchar cha ...

  6. HDU 1023 Train Problem II( 大数卡特兰 )

    链接:传送门 题意:裸卡特兰数,但是必须用大数做 balabala:上交高精度模板题,增加一下熟悉度 /************************************************ ...

  7. BZOJ 3295 [CQOI2011]动态逆序对 (三维偏序CDQ+树状数组)

    题目大意: 题面传送门 还是一道三维偏序题 每次操作都可以看成这样一个三元组 $<x,w,t>$ ,操作的位置,权值,修改时间 一开始的序列看成n次插入操作 我们先求出不删除时的逆序对总数 ...

  8. [WPF] 圆形等待效果

    原文:[WPF] 圆形等待效果 自己做着玩儿的,留着以后用,效果类似下面的 GIF 动画. <Grid Width="35" Height="35"> ...

  9. 【Codeforces Round #482 (Div. 2) C】Kuro and Walking Route

    [链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] 把x..y这条路径上的点标记一下. 然后从x开始dfs,要求不能走到那些标记过的点上.记录节点个数为cnt1(包括x) 然后从y开始 ...

  10. ASP.NET-使用json

    数据格式 vat strJson =' {"name":"jingya","Age":88} '; // 数字不用写双引号 JSON.par ...