题目描述
H 国有 n 个城市,这 n 个城市用 n-1 条双向道路相互连通构成一棵树,1 号城市是首都,
也是树中的根节点。
H 国的首都爆发了一种危害性极高的传染病。当局为了控制疫情,不让疫情扩散到边境
城市(叶子节点所表示的城市),决定动用军队在一些城市建立检查点,使得从首都到边境
城市的每一条路径上都至少有一个检查点,边境城市也可以建立检查点。但特别要注意的是,
首都是不能建立检查点的。
现在,在 H 国的一些城市中已经驻扎有军队,且一个城市可以驻扎多个军队。一支军队可以在有道路连接的城市间移动,并在除首都以外的任意一个城市建立检查点,且只能在
一个城市建立检查点。一支军队经过一条道路从一个城市移动到另一个城市所需要的时间等
于道路的长度(单位:小时)。
请问最少需要多少个小时才能控制疫情。注意:不同的军队可以同时移动。
输入输出格式
输入格式:第一行一个整数 n,表示城市个数。
接下来的 n-1 行,每行 3 个整数,u、v、w,每两个整数之间用一个空格隔开,表示从
城市 u 到城市 v 有一条长为 w 的道路。数据保证输入的是一棵树,且根节点编号为 1。
接下来一行一个整数 m,表示军队个数。
接下来一行 m 个整数,每两个整数之间用一个空格隔开,分别表示这 m 个军队所驻扎
的城市的编号。
输出格式:共一行,包含一个整数,表示控制疫情所需要的最少时间。如果无法控制疫情则输出-1。
输入输出样例
4 1 2 1 1 3 2 3 4 3 2 2 2
3
说明
【输入输出样例说明】
第一支军队在 2 号点设立检查点,第二支军队从 2 号点移动到 3 号点设立检查点,所需
时间为 3 个小时。
【数据范围】
保证军队不会驻扎在首都。
对于 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。
NOIP 2012 提高组 第二天 第三题
#include<algorithm>
#include<iostream>
#include<cstring>
#include<vector>
#include<cstdio>
using namespace std;
const int N=50005;
struct node
{
int ori;
long long val;
}tim[N],tmp;
vector<node>nd;
int n,m,cnt,hd[N],arm[N],dep[N],f[N][21],pre[N];
long long dis[N];
bool b[N],bb[N];
struct edge
{
int to,nxt;
long long val;
}v[2*N];
void addedge(int x,int y,long long z)
{
++cnt;
v[cnt].to=y;
v[cnt].nxt=hd[x];
v[cnt].val=z;
hd[x]=cnt;
}
bool cmp(node c,node d)
{
return c.val<d.val;
}
int cb(int u)
{
for(int i=15;i>=0;i--)
if(dep[f[u][i]]>1)
u=f[u][i];
return u;
}
void build(int u,int fa)
{
for(int i=hd[u];i;i=v[i].nxt)
if(v[i].to!=fa)
{
f[v[i].to][0]=u;
dis[v[i].to]=dis[u]+v[i].val;
dep[v[i].to]=dep[u]+1;
build(v[i].to,u);
}
}
bool dfs(int u,int fa)
{
if(u==1)
{
bool flg=0;
for(int i=hd[1];i;i=v[i].nxt)
if(!dfs(v[i].to,u))
{
bb[v[i].to]=1;
tmp.ori=v[i].to,tmp.val=dis[v[i].to];
nd.push_back(tmp);
flg=1;
}
if(flg)
return 0;
return 1;
}
if(b[u])
return 1;
bool flg=0;
for(int i=hd[u];i;i=v[i].nxt)
if(v[i].to!=fa)
if(!dfs(v[i].to,u))
return 0;
else
flg=1;
if(flg)
return 1;
return 0;
}
bool pd(long long lim)
{
nd.clear();
int cnt=0;
memset(tim,0,sizeof(tim));
memset(b,0,sizeof(b));
memset(bb,0,sizeof(bb));
for(int i=1;i<=m;i++)
{
int t=arm[i];
long long lft=lim;
for(int j=16;j>=0;j--)
if(dep[f[t][j]]>0&&dis[t]-dis[f[t][j]]<=lft)
lft-=dis[t]-dis[f[t][j]],t=f[t][j];
if(t==1)
tim[++cnt].val=lft,tim[cnt].ori=arm[i];
else
b[t]=1;
}
if(dfs(1,0))
return 1;
sort(tim+1,tim+cnt+1,cmp);
sort(nd.begin(),nd.end(),cmp);
int k=0;
for(int i=1;i<=cnt;i++)
{
if(bb[pre[tim[i].ori]])
bb[pre[tim[i].ori]]=0;
else
{
while(k<nd.size()&&!bb[nd[k].ori])
k++;
if(nd[k].val<=tim[i].val)
bb[nd[k].ori]=0;
}
}
for(int i=0;i<=nd.size()-1;i++)
if(bb[nd[i].ori])
return 0;
return 1;
}
int main()
{
scanf("%d",&n);
long long l=0,r=0,mid;
for(int i=1;i<=n-1;i++)
{
int x,y;
long long z;
scanf("%d%d%lld",&x,&y,&z);
addedge(x,y,z);
addedge(y,x,z);
r+=z;
}
dep[1]=1;
build(1,0);
for(int i=1;i<=16;i++)
for(int j=1;j<=n;j++)
f[j][i]=f[f[j][i-1]][i-1];
scanf("%d",&m);
for(int i=1;i<=m;i++)
{
scanf("%d",&arm[i]);
pre[arm[i]]=cb(arm[i]);
}
while(l<r)
{
mid=(l+r)/2;
if(!pd(mid))
l=mid+1;
else
r=mid;
}
if(pd(l))
printf("%lld\n",l);
else
printf("-1\n");
return 0;
}