【noip 2012】提高组Day2T3.疫情控制
Description
H国有n个城市,这n个城市用n-1条双向道路相互连通构成一棵树,1号城市是首都,也是树中的根节点。
H国的首都爆发了一种危害性极高的传染病。当局为了控制疫情,不让疫情扩散到边境城市(叶子节点所表示的城市),决定动用军队在一些城市建立检查点,使得从首都到边境城市的每一条路径上都至少有一个检查点,边境城市也可以建立检查点。但特别要注意的是,首都是不能建立检查点的。
现在,在H国的一些城市中已经驻扎有军队,且一个城市可以驻扎多个军队。一支军队可以在有道路连接的城市间移动,并在除首都以外的任意一个城市建立检查点,且只能在一个城市建立检查点。一支军队经过一条道路从一个城市移动到另一个城市所需要的时间等于道路的长度(单位:小时)。
请问最少需要多少个小时才能控制疫情。注意:不同的军队可以同时移动。
Input
第一行一个整数n,表示城市个数。
接下来的n-1行,每行3个整数,u、v、w,每两个整数之间用一个空格隔开,表示从城市u到城市v有一条长为w的道路。数据保证输入的是一棵树,且根节点编号为1。
接下来一行一个整数m,表示军队个数。
接下来一行m个整数,每两个整数之间用一个空格隔开,分别表示这m个军队所驻扎的城市的编号。
Output
共一行,包含一个整数,表示控制疫情所需要的最少时间。如果无法控制疫情则输出-1。
Sample Input
4
1 2 1
1 3 2
3 4 3
2
2 2
Sample Output
3
HINT
保证军队不会驻扎在首都。
对于20%的数据,2≤ n≤ 10;
对于40%的数据,2 ≤n≤50,0<w <10^5;
对于60%的数据,2 ≤ n≤1000,0<w <10^6;
对于80%的数据,2 ≤ n≤10,000;
对于100%的数据,2≤m≤n≤50,000,0<w <10^9。
A了这道题之后无意中发现可以把自己的代码hack掉(放出的代码是已经修改完的,啊当然有可能还会被hack掉)
以下是数据:2 1 2 5 1 2,应输出0。
这组数据也可以hack掉网上的很多题解……然而vijos和codevs都没卡。
方法是二分+贪心+拓扑排序/倍增,这里用的是拓扑排序。
贪心可得,每个军队尽量要往上走。二分出mid之后,走不到根节点的军队就走到他们所能到达的最靠近根节点的节点,能走到根节点的军队则扔进一个队列里,再将根节点尚未被控制的子节点扔进另一个队列,每个子节点需要一支军队控制。贪心可得,将军队走到根节点后的剩余时间从小到大sort一发,再按根节点到子节点所需时间将子节点sort一发,一一匹配即可。
详见代码。
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#define ll long long
using namespace std;
const int N=;
int n,m,cnt,u,v,w,cnt1,cnt2,first[N];
int army[N],q[N],fa[N],anc[N],t1[N],t2[N];
//anc[i]代表控制节点i的根节点的子节点的编号
bool notl[N],arr[N],mark[N];
//arr[i]代表节点i的子树所包括的叶子结点是否全部被控制
ll l,r,tot,dis[N],cost[N],t[N];
//t[i]代表军队往上走到达节点i剩余时间最大值
struct edge{int next,to,w;}e[N*];
int read()
{
int x=,f=;char c=getchar();
while(c<''||c>''){if(c=='-')f=-;c=getchar();}
while(c>=''&&c<=''){x=x*+c-'';c=getchar();}
return x*f;
}
void ins(int u,int v,int w)
{
cnt++;e[cnt].to=v;e[cnt].w=w;
e[cnt].next=first[u];first[u]=cnt;
}
bool cmp1(int a,int b){return cost[a]<cost[b];}
bool cmp2(int a,int b){return dis[army[a]]>dis[army[b]];}
void bfs()
{
int h=,t=;q[++t]=;
while(h<=t)
{
int u=q[h++];
notl[u]=false;
for(int i=first[u];i;i=e[i].next)
{
int v=e[i].to;
if(v==fa[u])continue;
dis[v]=dis[u]+e[i].w;
fa[v]=u;cost[v]=e[i].w;//cost[i]代表节点i到其父节点所需时间
if(u!=)anc[v]=anc[u];
else anc[v]=v;
q[++t]=v;
notl[u]=true;
}
}
}
bool check(ll mid)
{
memset(t,-,sizeof(t));
for(int i=;i<=n;i++)arr[i]=notl[i];
for(int i=n;i;i--)//按bfs的顺序倒着处理
{
int u=q[i];
if(mark[u]&&dis[u]>mid)t[u]=mid;
if(t[fa[u]]<t[u]-cost[u])t[fa[u]]=t[u]-cost[u];
if(t[u]>=)arr[u]=true;
if(!arr[u])arr[fa[u]]=false;
//若军队能到达节点u或节点u的子树所包括的叶子结点已全部被控制,arr[u]=true
}
cnt1=cnt2=;
for(int i=first[];i;i=e[i].next)
if(!arr[e[i].to])t1[++cnt1]=e[i].to;//将根节点尚未被控制的子节点扔进队列
for(int i=;i<=m;i++)
if(dis[army[i]]<=mid)t2[++cnt2]=i;//将所有可以使用的军队扔进队列
if(cnt1==)return true;//若已经全部控制,则直接返回true
sort(t1+,t1+cnt1+,cmp1);
sort(t2+,t2+cnt2+,cmp2);
for(int i=,j=;i<=cnt2;i++)
{
if(!arr[anc[army[t2[i]]]])arr[anc[army[t2[i]]]]=true;
else if(cost[t1[j]]+dis[army[t2[i]]]<=mid)arr[t1[j]]=true;
while(j<=cnt1&&arr[t1[j]])j++;
if(j>cnt1)return true;
}
return false;
}
int main()
{
n=read();
for(int i=;i<n;i++)
{
u=read();v=read();w=read();
r+=w;ins(u,v,w);ins(v,u,w);
}
tot=r;
m=read();
for(int i=;i<=m;i++)
army[i]=read(),mark[army[i]]=true;
bfs();
while(l<=r)
{
ll mid=(l+r)/;
if(check(mid))r=mid-;
else l=mid+;
}
if(l==tot+)printf("-1");
else printf("%lld",l);
return ;
}
【noip 2012】提高组Day2T3.疫情控制的更多相关文章
- 洛谷P1084 [NOIP2012提高组Day2T3]疫情控制
P1084 疫情控制 题目描述 H 国有 n 个城市,这 n 个城市用 n-1 条双向道路相互连通构成一棵树,1 号城市是首都,也是树中的根节点. H 国的首都爆发了一种危害性极高的传染病.当局为了控 ...
- Vigenère 密码NOIP 2012 提高组 第一天 第一题
题目描述 16 世纪法国外交家 Blaise de Vigenère 设计了一种多表密码加密算法――Vigenère 密 码.Vigenère 密码的加密解密算法简单易用,且破译难度比较高,曾在美国南 ...
- noip 2012 提高组 day2 部分题解
这道题有多种解法,我用的是扩展欧几里得算法求到的答案 #include<iostream> #include<fstream> #include<cstdio> u ...
- NOIP 2008提高组第三题题解by rLq
啊啊啊啊啊啊今天已经星期三了吗 那么,来一波题解吧 本题地址http://www.luogu.org/problem/show?pid=1006 传纸条 题目描述 小渊和小轩是好朋友也是同班同学,他们 ...
- [NOIp 1998 提高组]Probelm 2 连接多位数【2011百度实习生笔试题】
/*====================================================================== [NOIp 1998 提高组]Probelm 2 连接 ...
- NOIP 2014 提高组 题解
NOIP 2014 提高组 题解 No 1. 生活大爆炸版石头剪刀布 http://www.luogu.org/problem/show?pid=1328 这是道大水题,我都在想怎么会有人错了,没算法 ...
- NOIP 2001 提高组 题解
NOIP 2001 提高组 题解 No 1. 一元三次方程求解 https://vijos.org/p/1116 看见有人认真推导了求解公式,然后猥琐暴力过的同学们在一边偷笑~~~ 数据小 暴力枚举即 ...
- 最优贸易 NOIP 2009 提高组 第三题
题目描述 C 国有 n 个大城市和 m 条道路,每条道路连接这 n 个城市中的某两个城市.任意两个 城市之间最多只有一条道路直接相连.这 m 条道路中有一部分为单向通行的道路,一部分 为双向通行的道路 ...
- NOIP 2006 提高组 t1 能量项链
题目描述 在Mars星球上,每个Mars人都随身佩带着一串能量项链.在项链上有N颗能量珠.能量珠是一颗有头标记与尾标记的珠子,这些标记对应着某个正整数.并且,对于相邻的两颗珠子,前一颗珠子的尾标记一定 ...
随机推荐
- [ZJOI2016]小星星&[SHOI2016]黑暗前的幻想乡(容斥)
这两道题思路比较像,所以把他们放到一块. [ZJOI2016]小星星 题目描述 小Y是一个心灵手巧的女孩子,她喜欢手工制作一些小饰品.她有n颗小星星,用m条彩色的细线串了起来,每条细线连着两颗小星星. ...
- bzoj4337树的同构
树是一种很常见的数据结构. 我们把N个点,N-1条边的连通无向图称为树. 若将某个点作为根,从根开始遍历,则其它的点都有一个前驱,这个树就成为有根树. 对于两个树T1和T2,如果能够把树T1的所有点重 ...
- kafka集群图形界面管理工具kafka-manager
应用说明: 图形web相对于命令行很多时候显得更直观,kafka-manager是yahoo开源出来的项目,web界面还挺好用,安装更是很便捷. 安装环境: 具体安装: 1. 下载已经编译好的zip包 ...
- pycharm安装TensorFlow
一.首先说下我在安装TensorFlow的过程中遇到的坑: 1.python的版本是3.5的版本,因为TensorFlow好像只支持到3.5现在.然后python需要安装64位的安装包,如果安装的是3 ...
- 树结构关系的数据导出为excel
该文针对的是关于树结构的数据的导出,每一个节点都可以创建不定数的子节点,在选择好某个节点进行导出 时,会把该节点以及子节点的数据都导出来.导出后的excel的格式大概如下图的形式,这个是一个比较理想 ...
- 有趣的js获取input标签中光标的索引
先看动图如下,我们就可以很清楚的知道获取input标签中光标的索引的意思了. 由于IE支持document.selection,Firefox,Chrome,Safari以及Opera都有select ...
- python赋值和生成器
在python赋值过程中,对单个变量的赋值,在所有语言中都是通用的,如果是对两个变量同时进行赋值,这个时候,就会出现一点点小的差异.例如在下面的一两行代码中. a , b = b , a+b 这是同时 ...
- Python模块初识
目录 一 模块初识 二 模块分类 三 导入模块 四 Python文件的两种用途 五 模板查找顺序 六 软件开发目录规范 一.模块初识 模块是自我包含并且有组织的代码片段,是一系列功能的集合体,一个py ...
- SqlServer查询Excel中的数据
步骤如下: --1.开启远程查询支持 reconfigure reconfigure --2.链接Excel Microsoft ACE 12.0 OLE DB Provider 读Excel数据(注 ...
- 解析:为什么设计师选择mac电脑居多?
mac电脑的使用者中程序员和设计师居多,上篇文章说明了程序员选择mac的原因以及使用体验,这次,本文说明一下,设计师选择mac的原因. 解析:为什么程序员应该有一台Mac个人电脑? 1.外观. 设计师 ...