【NOIP2012】 疫情控制
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
样例说明:
第一支军队在 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
#include<iostream> #include<stdio.h> #include<stdlib.h> #include<algorithm> #include<cstring> #define ll long long using namespace std; const int MAXN=50100; int st[MAXN][23];ll dis[MAXN][23]; int place[MAXN],Max[MAXN],zui[MAXN],mark[MAXN];bool b[MAXN],flag=1; int wei[MAXN],bb[MAXN],fr[MAXN]; int hh=0,h=0,markk=0; int n,m,num=0;ll tot=0; struct edge{ int first,next,to,quan; }a[MAXN*2]; struct date{ int from,x; }rest[MAXN]; struct data{ int from,x; }cost[MAXN]; bool cmp1(data x,data y){return x.x<y.x;} bool cmp2(date x,date y){return x.x<y.x;} void cl(){ memset(wei,0,sizeof(wei)); memset(rest,0,sizeof(rest)); memset(st,0,sizeof(st)); memset(dis,0,sizeof(dis)); } void addedge(int from,int to,int quan){ a[++num].to=to,a[num].quan=quan; a[num].next=a[from].first,a[from].first=num; } void dfs1(int now,int fa){ if(fa==1) markk=now; if(markk) wei[now]=markk; for(int i=a[now].first;i;i=a[i].next){ int to=a[i].to,quan=a[i].quan; if(to==fa) continue; st[to][0]=now,dis[to][0]=quan; dfs1(to,now); } } void dfs(int now,int fa,int can){ int son=0; for(int i=a[now].first;i;i=a[i].next){ int to=a[i].to; if(to==fa) continue; son++; if(fa==1&&b[now]) dfs(to,now,1); else if(b[to]) dfs(to,now,1); else dfs(to,now,can); } if(son==0&&b[now]) can=1; if(son==0&&can==0) flag=0; } bool check(ll zong){ int hh=0,h=0; memset(fr,0,sizeof(fr)); memset(bb,0,sizeof(bb)); memset(cost,0,sizeof(cost)); memset(mark,0,sizeof(mark)); memset(b,0,sizeof(b)); memset(rest,0,sizeof(rest)); memset(Max,127,sizeof(Max)); memset(zui,0,sizeof(zui)); for(int hhh=1;hhh<=m;hhh++){ int now=place[hhh]; ll tott=0; for(int j=22;j>=0;j--){ if(tott+dis[now][j]<=zong) tott+=dis[now][j],now=st[now][j]; } if(now==1) { rest[++hh].x=zong-tott; rest[hh].from=wei[place[hhh]]; if(rest[hh].x<Max[wei[place[hhh]]]) Max[wei[place[hhh]]]=rest[hh].x,zui[wei[place[hhh]]]=hhh; } else b[now]=1; } for(int i=a[1].first;i;i=a[i].next){ int to=a[i].to,quan=a[i].quan;flag=1; dfs(to,1,0); if(!flag) cost[++h].x=quan,cost[h].from=to; } int now=1,j=1; sort(cost+1,cost+h+1,cmp1); sort(rest+1,rest+hh+1,cmp2); for(int i=1;i<=h;i++) fr[cost[i].from]=i; for(;j<=h;){ while(bb[j]) j++; if(now>hh) break; if(cost[j].x<=rest[now].x||(rest[now].x<cost[j].x&&rest[now].from==cost[j].from)) j++,now++; else {bb[fr[rest[now].from]]=1;now++;} } if(j>h) return 1; return 0; } int main(){ cl(); scanf("%d",&n); for(int i=1;i<n;i++){ int x,y,z;scanf("%d%d%d",&x,&y,&z); addedge(x,y,z),addedge(y,x,z);tot+=z; } scanf("%d",&m); for(int i=1;i<=m;i++) scanf("%d",&place[i]); dfs1(1,0);st[1][0]=1; for(int j=1;j<=22;j++) for(int i=1;i<=n;i++){ if(i==1) st[i][j]=1; else st[i][j]=st[st[i][j-1]][j-1]; dis[i][j]=dis[i][j-1]+dis[st[i][j-1]][j-1]; } ll l=0,r=tot,ans=1<<30,mid; while(l<=r){ mid=(l+r)/2; if(check(mid)) ans=mid,r=mid-1; else l=mid+1; } if(ans==1<<30) printf("-1"); else printf("%lld",ans); }