题面

这道题由于问最大值最小,所以很容易想到二分,但怎么验证并且如何实现是这道题的难点;

首先我们考虑,对于一个军队,尽可能的往根节点走(但一定不到)是最优的;

判断一个军队最远走到哪可以树上倍增来实现;

但是,这并没有结束,因为可能这颗子树的军队会去另一个军队;

我们先找出所有以根节点的子节点为根的子树中,是否有到叶子节点的路径还未被驻扎,并记录下还有路径未被驻扎的这些子树的根节点;

若该节点上停留有军队,则剩余时间最小的军队驻扎在该节点一定是最优的。

这样处理过这些节点后,把剩下的节点按照到根节点的距离从小到大排序。

对于现在闲置的军队和需要被驻扎的节点,让剩余时间小的军队优先驻扎在距离根节点近的节点,这样可以保证决策最优

#include <bits/stdc++.h>
using namespace std;
const int MXR=5e4+2;
int n,m,t,tot=0,atot=0,btot=0,ctot=0;
int d[MXR],query[MXR],f[MXR][20];
int ver[2*MXR],edge[2*MXR],MXRext[2*MXR],head[MXR],dist[MXR][20];
pair<long long,int> h[MXR];
void add(int x,int y,int z){
ver[++tot]=y,edge[tot]=z,MXRext[tot]=head[x],head[x]=tot;
}
void bfs()
{
queue<int> q;
q.push(1);
d[1]=1;
while(q.size()){
int x=q.front();q.pop();
for(int i=head[x];i;i=MXRext[i]){
int y=ver[i];
if(d[y]) continue;
d[y]=d[x]+1;
f[y][0]=x,dist[y][0]=edge[i];
for(int j=1;j<=t;j++){
f[y][j]=f[f[y][j-1]][j-1];
dist[y][j]=dist[y][j-1]+dist[f[y][j-1]][j-1];
}
q.push(y);
}
}
}
bool ok,sta[MXR],need[MXR];
long long ans,tim[MXR],ned[MXR];
int dfs(register int x)
{
bool pson=0;
if(sta[x]) return 1;
for(int i=head[x];i;i=MXRext[i]){
int y=ver[i];
if(d[y]<d[x]) continue;
pson=1;
if(!dfs(y)) return 0;
}
if(!pson) return 0;
return 1;
}
template<class nT>
inline void read(nT&x)
{
char c;while(c=getchar(),!isdigit(c));
x=c^48;while(c=getchar(),isdigit(c)) x=x*10+c-48;
}
bool check(long long lim)
{
memset(sta,0,sizeof(sta));
memset(tim,0,sizeof(tim));
memset(ned,0,sizeof(ned));
memset(h,0,sizeof(h));
memset(need,0,sizeof(need));
atot=0,btot=0,ctot=0;
for(int i=1;i<=m;i++){
long long x=query[i],cnt=0;
for(int j=t;j>=0;j--)
if(f[x][j]>1 && cnt+dist[x][j]<=lim){
cnt+=dist[x][j];
x=f[x][j];
}
if(f[x][0]==1 && cnt+dist[x][0]<=lim) h[++ctot]=make_pair(lim-cnt-dist[x][0],x);
else sta[x]=1;
}
for(int i=head[1];i;i=MXRext[i]) if(!dfs(ver[i])) need[ver[i]]=1;
sort(h+1,h+ctot+1);
for(int i=1;i<=ctot;i++){
if(need[h[i].second] && h[i].first<dist[h[i].second][0]) need[h[i].second]=0;
else tim[++atot]=h[i].first;
}
for(int i=head[1];i;i=MXRext[i]) if(need[ver[i]]) ned[++btot]=dist[ver[i]][0];
if(atot<btot) return 0;
sort(tim+1,tim+atot+1),sort(ned+1,ned+btot+1);
int i=1,j=1;
while(i<=btot && j<=atot)
if(tim[j]>=ned[i]){
i++,j++;
}
else j++;
if(i>btot)return 1;
return 0;
}
int main()
{
long long l=0,r=0,mid;
cin>>n;
t=log2(n)+1;
for(int i=1;i<=n-1;i++){
int x,y,z;
read(x); read(y); read(z);
add(x,y,z),add(y,x,z);
r+=z;
}
bfs();
cin>>m;
for(int i=1;i<=m;i++) read(query[i]);
while(l<=r){
mid=(l+r)>>1;
if(check(mid)){
r=mid-1;
ans=mid;
ok=1;
}
else
l=mid+1;
}
if(!ok) cout<<-1;
else cout<<ans;
return 0;
}

NOIP2012 D2T3 疫情控制 题解的更多相关文章

  1. NOIP2012 疫情控制 题解(LuoguP1084)

    NOIP2012 疫情控制 题解(LuoguP1084) 不难发现,如果一个点向上移动一定能控制更多的点,所以可以二分时间,判断是否可行. 但根节点不能不能控制,存在以当前时间可以走到根节点的点,可使 ...

  2. 【NOIP2012】 疫情控制

    [NOIP2012] 疫情控制 标签: 倍增 贪心 二分答案 NOIP Description H 国有 n 个城市,这 n 个城市用 n-1 条双向道路相互连通构成一棵树, 1 号城市是首都, 也是 ...

  3. luoguP1084 疫情控制(题解)(搜索+贪心)

    luoguP1084 疫情控制 题目 #include<iostream> #include<cstdlib> #include<cstdio> #include& ...

  4. [NOIp2012]疫情控制 题解

    好久没更,强迫自己写一篇. 神 tm 大预言家出的题 注意到如果 \(x\) 小时可以控制住疫情,则 \(\forall x'>x\) 必然也可以控制住疫情,显然答案具有单调性,可以二分答案. ...

  5. noip2012疫情控制 题解

    题目大意 给出一棵n个节点的树,根是1,要在除根节点以外的点建立检查点,使得从每条根到叶子的路径上都至少存在一个检查点.检查点由军队来建立.初始军队的位置是给定的,移动军队走一条边需要花费这条边的权值 ...

  6. [LOJ2607]【NOIP2012】疫情控制

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

  7. 【noip2012】疫情控制

    题意: 给出一颗n个节点有边权的树 和m个军队所在的位置 军队从某节点移动到相邻节点要花费边长度的时间 求最少要多少时间使得根节点(编号为1)到每个叶子的路径上最少有一支军队(根节点不能有军队) 题解 ...

  8. 【NOIP2012】疫情控制(二分,倍增,贪心)

    洛谷上的题目链接,题目不在赘述 题解 既然要时间最短,首先考虑二分. 因此,考虑二分时间,问题转换为如何检查能否到达. 如果一支军队一直向上走,能够到达根节点,那么他可以通过根节点到达其他的节点,因此 ...

  9. [NOIP2012]疫情控制 贪心 二分

    题面:[NOIP2012]疫情控制 题解: 大体思路很好想,但是有个细节很难想QAQ 首先要求最大时间最小,这种一般都是二分,于是我们二分一个时间,得到一个log. 然后发现一个军队,越往上走肯定可以 ...

随机推荐

  1. Visualizing and Understanding Convolutional Networks

    前言:研究卷积神经网络,把阅读到的一些文献经典的部分翻译一下,写成博客,代码后续给出,不足之处还请大家指出. 本文来自:tony-tan.com Github:github.com/Tony-Tan ...

  2. websocket 连接测试端口服务是否正常代码

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  3. 9030PCI CAN驱动开发点滴

    1.配置EEPROM. 使用PlxMon打开9030,基本修改Spacex(0,1,2,3), Chip selectx(0,1,2,3), 中断状态INTCSR(0x74), 其他(0x78),详细 ...

  4. Ubuntu下的redis安装过程

    Redis make test Errors? - Stack Overflow  https://stackoverflow.com/questions/48425998/redis-make-te ...

  5. 树状数组(BIT)

    树状数组 树状数组是在线段树的结构上改造而来数据结构,主要用于完成: 给定一个初始值全为0的数列 ①给定i,计算返回a1+a2+--+ai的值 ②给定i和x,执行ai+=x BIT的求和 ll sum ...

  6. [洛谷P3941]:入阵曲(前缀和+桶)

    题目传送门 题目背景 丹青千秋酿,一醉解愁肠.无悔少年枉,只愿壮志狂. 题目描述 小$F$很喜欢数学,但是到了高中以后数学总是考不好.有一天,他在数学课上发起了呆:他想起了过去的一年.一年前,当他初识 ...

  7. leetcode题目17.电话号码的字母组合(中等)

    题目描述: 给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合. 给出数字到字母的映射如下(与电话按键相同).注意 1 不对应任何字母. 示例: 输入:"23"输出: ...

  8. C++ 编程风格指南

    C++ Programming Style Guidelines 他人翻译中文版:click 让程序具有好的可读性 “避免日后 有人(或者自己)指着你的代码骂娘:这特么谁写的破烂 玩意”(来自:知乎- ...

  9. window 下要运行php,需要编辑php环境变量

    参考:https://blog.csdn.net/zhezhebie/article/details/72765262

  10. laravel 文件上传总结

    调用 store 方法会生成唯一的 ID 来作为文件名,如果想获取原件本来的名称可以使用 $file = $request->file('file'); $file->getClientO ...