【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颗能量珠.能量珠是一颗有头标记与尾标记的珠子,这些标记对应着某个正整数.并且,对于相邻的两颗珠子,前一颗珠子的尾标记一定 ...
随机推荐
- Windows Update第三方工具概览
受方程式黑客组织0Day攻击影响,所有的Windows服务器都要更新补丁. 方程式0day漏洞攻击介绍:https://zhuanlan.zhihu.com/p/26375989 腾讯云的解决方案:h ...
- empty() 与 html("") 的区别
empty,首先循环给后代元素移除绑定.清除jquery给此dom的cache,然后循环removeFirstChild. 而html(''),则是简单暴力的设置innerHTML = ''; 查看文 ...
- 2018.02.12 noip模拟赛T2
二兵的赌注 Description游戏中,二兵要进入了一家奇怪的赌场.赌场中有n个庄家,每个庄家都可以猜大猜小,猜一次一元钱.每一次开彩前,你都可以到任意个庄家那里下赌注.如果开彩结果是大,你就可以得 ...
- 【CF600E】Lomsat gelral
题目大意:给定一棵 N 个节点的有根树,1 号节点是树的根节点,每个节点有一个颜色.求对于每个节点来说,能够支配整棵子树的颜色之和是多少.支配的定义为对于以 i 为根的子树,该颜色出现的次数不小于任何 ...
- 数据库和Django model 生成和反向生成
Django 脚本生成数据表 建立映射关系 如果询问时区时间,选1 然后输入timezone.now() python manage.py makemigrations (如果有子应用的话子应用名称填 ...
- 1.Ubuntu系统与vmware虚拟机的安装与使用
1.下载Ubuntu的镜像文件 种子文件的下载页面的链接:https://www.ubuntu.com/download/alternative-downloads 可以去选择版本的桌面版(Deskt ...
- 关于shared_ptr与weak_ptr的使用(good)
shared_ptr是带引用计数的智能指针,可以说大部分的情形选择用shared_ptr不会出问题.那么weak_ptr是什么,应该怎么用呢? weak_ptr也是智能指针,但是比较弱,感觉没什么用. ...
- opencv: 角点检测源码分析;
以下6个函数是opencv有关角点检测的函数 ConerHarris, cornoerMinEigenVal,CornorEigenValsAndVecs, preConerDetect, coner ...
- jmeter5.0 while controller使用总结
while controller 配合sql使用的方式 在while控制器条件中填空,这样当里面的请求断言失败后就会跳出循环 在while控制器条件中填LAST,当里面的请求断言失败后就会跳出循环,如 ...
- OGNL中的#、%和$符号的用法
转自:https://blog.csdn.net/qq_24963197/article/details/51773224 一.OGNL中的#.%和$符号 1.#符号的三种用法 1)访问非根对象属性, ...