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.疫情控制的更多相关文章

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

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

  2. Vigenère 密码NOIP 2012 提高组 第一天 第一题

    题目描述 16 世纪法国外交家 Blaise de Vigenère 设计了一种多表密码加密算法――Vigenère 密 码.Vigenère 密码的加密解密算法简单易用,且破译难度比较高,曾在美国南 ...

  3. noip 2012 提高组 day2 部分题解

    这道题有多种解法,我用的是扩展欧几里得算法求到的答案 #include<iostream> #include<fstream> #include<cstdio> u ...

  4. NOIP 2008提高组第三题题解by rLq

    啊啊啊啊啊啊今天已经星期三了吗 那么,来一波题解吧 本题地址http://www.luogu.org/problem/show?pid=1006 传纸条 题目描述 小渊和小轩是好朋友也是同班同学,他们 ...

  5. [NOIp 1998 提高组]Probelm 2 连接多位数【2011百度实习生笔试题】

    /*====================================================================== [NOIp 1998 提高组]Probelm 2 连接 ...

  6. NOIP 2014 提高组 题解

    NOIP 2014 提高组 题解 No 1. 生活大爆炸版石头剪刀布 http://www.luogu.org/problem/show?pid=1328 这是道大水题,我都在想怎么会有人错了,没算法 ...

  7. NOIP 2001 提高组 题解

    NOIP 2001 提高组 题解 No 1. 一元三次方程求解 https://vijos.org/p/1116 看见有人认真推导了求解公式,然后猥琐暴力过的同学们在一边偷笑~~~ 数据小 暴力枚举即 ...

  8. 最优贸易 NOIP 2009 提高组 第三题

    题目描述 C 国有 n 个大城市和 m 条道路,每条道路连接这 n 个城市中的某两个城市.任意两个 城市之间最多只有一条道路直接相连.这 m 条道路中有一部分为单向通行的道路,一部分 为双向通行的道路 ...

  9. NOIP 2006 提高组 t1 能量项链

    题目描述 在Mars星球上,每个Mars人都随身佩带着一串能量项链.在项链上有N颗能量珠.能量珠是一颗有头标记与尾标记的珠子,这些标记对应着某个正整数.并且,对于相邻的两颗珠子,前一颗珠子的尾标记一定 ...

随机推荐

  1. [SDOI2011]消防

    某个国家有n个城市,这n个城市中任意两个都连通且有唯一一条路径,每条连通两个城市的道路的长度为zi(zi<=1000). 这个国家的人对火焰有超越宇宙的热情,所以这个国家最兴旺的行业是消防业.由 ...

  2. 关于servlet连接数据库会出现空指针异常情况

    一.servlet在连接数据库时,如果没有事先配置,当用Tomcat运行时会出现NullPointer的情况,是因为Tomcat在运行你的应用程序时没有连接mysql的jar包, 正确做法是将你的my ...

  3. socket,tcp,http三者之间的区别和原理

    http.TCP/IP协议与socket之间的区别下面的图表试图显示不同的TCP/IP和其他的协议在最初OSI模型中的位置: 7 应用层 例如HTTP.SMTP.SNMP.FTP.Telnet.SIP ...

  4. Docker安装及常用命令

    修改机器名: [root@docker /]# hostnamectl set-hostname Docker 安装EPEL源: [root@docker /]# yum -y install epe ...

  5. js 判断字符串中是否包含某个字符串

    String对象的方法 方法一: indexOf()   (推荐) var str = "123"; console.log(str.indexOf("3") ...

  6. ArcGIS for qml -添加自由文本

    源码:https://github.com/sueRimn/ArcGIS-for-qml-demos 实现地图上鼠标点击后添加自由文本功能 作者: 狐狸家的鱼 Github: 八至 版权声明:如需转载 ...

  7. A1112. Stucked Keyboard

    On a broken keyboard, some of the keys are always stucked. So when you type some sentences, the char ...

  8. 【洛谷P3917】异或序列

    题目大意:给定一个长度为 N 的序列,每个位置有一个权值,求 \[\sum\limits_{1\le i\le j\le n}(a_i\oplus a_{i+1}...\oplus a_j)\] 的值 ...

  9. Django 分页器的使用

    Django 分页器的使用 Django作为Python Web开发框架的一哥,提供了企业级网站开发所需要的几乎所有功能,其中就包括自带分页功能.利用Django自带的Paginator类,我们可以很 ...

  10. Redis命令:scan实现模糊查询

    转: Redis命令:scan实现模糊查询 2017年12月31日 16:54:33 琦彦 阅读数:22893 标签: redis数据库Redis命令scan模糊查询 更多 个人分类: Redis 所 ...