NOIP2012 疫情控制

题目描述 Description

H 国有 n 个城市,这 n 个城市用 n-1 条双向道路相互连通构成一棵树,1 号城市是首都,

也是树中的根节点。

H 国的首都爆发了一种危害性极高的传染病。当局为了控制疫情,不让疫情扩散到边境

城市(叶子节点所表示的城市),决定动用军队在一些城市建立检查点,使得从首都到边境

城市的每一条路径上都至少有一个检查点,边境城市也可以建立检查点。但特别要注意的是,

首都是不能建立检查点的。

现在,在 H国的一些城市中已经驻扎有军队,且一个城市可以驻扎多个军队。一支军

队可以在有道路连接的城市间移动,并在除首都以外的任意一个城市建立检查点,且只能在

一个城市建立检查点。一支军队经过一条道路从一个城市移动到另一个城市所需要的时间等

于道路的长度(单位:小时)。

请问最少需要多少个小时才能控制疫情。注意:不同的军队可以同时移动。

 

输入描述 Input Description

第一行一个整数 n,表示城市个数。

接下来的 n-1 行,每行 3 个整数,u、v、w,每两个整数之间用一个空格隔开,表示从

城市 u 到城市 v 有一条长为 w 的道路。数据保证输入的是一棵树,且根节点编号为 1。

接下来一行一个整数 m,表示军队个数。

接下来一行 m 个整数,每两个整数之间用一个空格隔开,分别表示这 m 个军队所驻扎

的城市的编号。

输出描述 Output Description

共一行,包含一个整数,表示控制疫情所需要的最少时间。如果无法控制疫情则输出-1。

样例输入 Sample Input

1 2 1 

1 3 2 

3 4 3 

2 2 

样例输出 Sample Output

3

数据范围及提示 Data Size & 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。

//copy
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <set>
#include <map>
#include <algorithm>
#include <cmath>
using namespace std;
const int maxn = 100000;
typedef long long LL;
multiset<int> S;
multiset<int>::iterator it;
int n,u,v,w,m,nownode;
LL f[maxn][20];
int y[maxn];
int g[maxn][20];
int sonTree[maxn];
int cnt[maxn];
int p[maxn];
int Min[maxn]; 
bool Leaf[maxn];
bool son[maxn];
struct    Arm
{
          int opt,time;
}A[maxn]; 
struct    Graph
{
     int node[maxn * 2], len[maxn * 2], next[maxn * 2], v[maxn * 2];
     int en;
     Graph(){ 
        memset(v,0,sizeof(v));
        memset(next,0, sizeof(next));
        memset(len,0,sizeof(len));  
        en  = 0; 
     }
     void   addEdge(int a,int b,int c)
     {
            en++; node[en] = b; len[en] = c; next[en] = v[a]; v[a] = en;
            en++; node[en] = a; len[en] = c; next[en] = v[b]; v[b] = en;
     }
}G;
void     DFS(int x,int father)
{
         sonTree[x] = nownode;
         bool flag= true;
         for (int j = G.v[x]; j; j = G.next[j])
         {
             if (G.node[j] != father)
             {
                 //father[j] = x;
                 flag = false;
                 f[G.node[j]][0] = G.len[j];
                 g[G.node[j]][0] = x;
                 if (x==1) nownode = G.node[j];
                 DFS(G.node[j],x); 
             }
         }
         Leaf[x] = flag;
}
void     find_leaf(int x, int father)
{
         if (cnt[x]>0) return ;
         if (Leaf[x])
         {
             son[nownode] = true;
             return;
         }
         for (int j = G.v[x]; j ; j = G.next[j])
         {
             if (G.node[j] != father)
             {
                 if (x==1) nownode = G.node[j];
                 find_leaf(G.node[j], x);
             }
         }
}
bool     ok(LL value)
{
    S.clear();
    int arm = 0;
    memset(cnt,0,sizeof(cnt));
    memset(son,0,sizeof(son));
    for (int i = 1; i <= m ;++i)
    {
        int len = value;
        int Pos = p[i];
        for (int j = 16; j>=0; --j)
            {
                 if (f[Pos][j]<=len && g[Pos][j]!=0)
                 {
                     len-=f[Pos][j];
                     Pos =g[Pos][j];              
                 }
            }
        if (Pos == 1)
        {
            A[arm].opt = p[i];
            A[arm++].time  = len;
        } else
          cnt[Pos]++;
    }           
    find_leaf(1,0); 
    for (int i = 1;i <= n;++i) Min[i]= -1;
    for (int i = 0; i < arm ; ++ i)
    {
        if (son[sonTree[A[i].opt]])
        {
           if  (Min[sonTree[A[i].opt]] ==-1 || 
              A[Min[sonTree[A[i].opt]]].time > A[i].time)
                Min[sonTree[A[i].opt]] = i;
        }
    } 
    int tot = 0;
    for (int i = 1; i <= n;++i)
    {
        if (son[i] && Min[i] != -1 && A[Min[i]].time<f[i][0])
        {
            A[Min[i]].time = -1;       
        }else
        if (son[i]) y[tot++] = f[i][0];
    }
    sort(y,y+tot);
    for (int i = 0; i < arm;++i)
    if (A[i].time != -1)
        S.insert(A[i].time);
        
    for (int i = tot-1; i>=0; --i)
    {
        if (S.lower_bound(y[i]) == S.end()) return false;
        it = S.lower_bound(y[i]);
        S.erase(it);
    }
    return true;
}
int main()
{
    cin>>n;
    for (int i = 1;i < n;++ i)
    {
        scanf("%d %d %d",&u,&v,&w);
        G.addEdge(u,v,w);
    }
    cin>>m ;
    for (int i = 1;i <= m;++i)
    {
        scanf("%d", &p[i]);
        // cnt[p[i]] ++;
    }
    DFS(1,0);
    /*for (int i = 1;i <= n; ++i)
    {
        cout <<i<<" "<<f[i][0]<<" "<<g[i][0] << endl; 
    }*/
    for (int i = 1; i <=16; ++i)
        for (int j = 1; j <= n ;++j)
        {
            f[j][i] = f[j][i-1]+ f[g[j][i-1]][i-1];
            g[j][i] = g[g[j][i-1]][i-1];
        }
    
    
    LL L = 0 , R = (LL)n * round(10e9);
    int ans = -1;
    while (L <= R)
    {
          LL mid = (L+R) /2;
          if (ok(mid)) R = mid-1, ans = mid; 
          else L = mid+1;
    }
    cout << ans << endl;
    return 0;
}

 

posted @ 2016-09-08 11:43  ACforever  阅读(403)  评论(0编辑  收藏  举报