【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


1 2 1 
1 3 2 
3 4 3 

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

 
题解:
看了题解,又浪费一道好题。
首先,我们要想对于这道题,我们可以先二分一下,把这个问题转化成一个可行性问题,然后对于到的了跟的军队,记录一下他剩下可以走的距离,如果一个点不能走到根,那么越向上,那么肯定他可以控制的节点就必定越多,所以对于跳不到根节点的军队,肯定尽量向上走。把他能走到的最高节点打个标记,dfs或者拓扑检查一下只用跳不上跟的军队还有,对于根,还有多少颗子树还需要军队,然后就可以贪心选了;
就是:我们先把需要军队的节点(他的爸爸是根),按照他到根的边权sort一遍,然后将走到根的军队按照剩余时间sort一遍,然后按顺序处理一下,显然当前节点一定是最没用的节点,要让他发挥最大的价值就和当前需控制的节点比较,如果能控制就控制,如果不能控制就控制当前他来的那颗子树。最后看一下能否全部控制就可以了。
就是这样check的。
然后跳就是倍增跳就可以了。
 
代码:
#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);
}

 

posted @ 2017-07-29 22:53  人间失格—太宰治  阅读(341)  评论(0编辑  收藏  举报