noip 2012 疫情控制

/*
考试的时候没想出正解 也没打暴力 时间不够了
随便yy了几种情况按出现的先后顺序处理而没有贪心
的了20分 不粘了
正解是围绕首都的儿子来搞的
显然先二分答案 对于每个限定的最大时间
我们尝试着那每个军队向根节点蹦 能蹦到的记下来最靠近根的点 并记下剩下多少时间
不能蹦到的 记下能蹦到哪里 并且标记为已有军队
最后updata一下不能蹦到的 说不定可以蹦到首都的儿子 或者首都的儿子的儿子都能蹦到
这里自己脑补一下图吧 很好理解的
然后我们就有了一些需要军队驻扎的首都的儿子还有到能到首都的军队及剩下的时间
然后开始分配 这里我们贪心的来搞
枚举还能移动的军队 首先看看他来的那个儿子是否需要军队 如果需要就过去
否则的话移动到它刚刚能到的最近的
最后统计一下是不是所有的需要军队的首都的儿子都有军队了

*/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define maxn 50010
using namespace std;
int n,m,num,head[maxn],fa[maxn][25],dis[maxn][20],f[maxn],ans=-1;
int p[maxn],sc,sg;
struct Children
{
    int t,c;
}cl[maxn];
struct Get
{
    int d,fr;
}get[maxn];
struct node
{
    int v,t,pre;
}e[maxn*2];
int cmp1(const Children &x,const Children &y)
{
    return x.t<y.t;
}
int cmp2(const Get &x,const Get &y)
{
    return x.d<y.d;
}
void Clear()
{
    memset(f,0,sizeof(f));
    sc=sg=0;
}
void Add(int from,int to,int dis)
{
    num++;e[num].v=to;
    e[num].t=dis;
    e[num].pre=head[from];
    head[from]=num;
}
void init()
{
    scanf("%d",&n);
    int x,y,z;
    for(int i=1;i<=n-1;i++)
      {
          scanf("%d%d%d",&x,&y,&z);
          Add(x,y,z);Add(y,x,z);
      }
}
void Dfs(int now,int from,int len)
{
    fa[now][0]=from;dis[now][0]=len;
    for(int i=head[now];i;i=e[i].pre)
      if(e[i].v!=from)
        Dfs(e[i].v,now,e[i].t);
}
void Get_fa()
{
    for(int j=1;j<=18;j++)
      for(int i=1;i<=n;i++)
        {
          fa[i][j]=fa[fa[i][j-1]][j-1];
          dis[i][j]=dis[i][j-1]+dis[fa[i][j-1]][j-1];
        }
}
void Up(int now,int from)
{
    int falg=0,isleaf=1;
    for(int i=head[now];i;i=e[i].pre)
      if(e[i].v!=from)
        {
            isleaf=0;Up(e[i].v,now);
            if(f[e[i].v]==0)falg=1;
        }
    if(!falg&&!isleaf)f[now]=1;
}
bool Judge(int x)
{
    Clear();
    for(int k=1;k<=m;k++)
      {
          int sum=0,a=p[k];
          for(int i=20;i>=0;i--)
            if(fa[a][i]&&sum+dis[a][i]<=x)
              {
                sum+=dis[a][i];
              a=fa[a][i];    
            }
        if(a!=1)f[a]=1;
        else 
          {
              cl[++sc].t=x-sum;a=p[k];
              for(int i=20;i>=0;i--)
                if(fa[a][i]>1)a=fa[a][i];
              cl[sc].c=a;
          }
      }
    Up(1,1);
    for(int i=head[1];i;i=e[i].pre)
      if(f[e[i].v]==0)
        {
          get[++sg].fr=e[i].v;
          get[sg].d=e[i].t;
        }
    sort(cl+1,cl+1+sc,cmp1);
    sort(get+1,get+1+sg,cmp2);
    int pi=1;
    for(int i=1;i<=sc;i++)
      {
          while(f[get[pi].fr])pi++;
          if(f[cl[i].c]==0)
            {
                f[cl[i].c]=1;
                continue;
          }
        if(cl[i].t>=get[pi].d)
          {
              f[get[pi].fr]=1;
              pi++;
          }
      }
    for(int i=1;i<=sg;i++)
      if(f[get[i].fr]==0)return 0;
    return 1;
    
}
void slove()
{
    scanf("%d",&m);
    for(int i=1;i<=m;i++)
      scanf("%d",&p[i]);
    int l=0,r=0x3f3f3f3f;
    while(l<=r)
      {
          int mid=(l+r)/2;
          if(Judge(mid))
            {
                r=mid-1;ans=mid;
          }
        else l=mid+1;
      }
    printf("%d\n",ans);
}
int main()
{
    //freopen("blockade.in","r",stdin);
    //freopen("blockade.out","w",stdout);
    init();
    Dfs(1,1,0);
    Get_fa();
    slove();
    return 0;
}

 

posted @ 2016-08-25 21:51  一入OI深似海  阅读(333)  评论(0编辑  收藏  举报