疫情控制(codevs 1218)

题目描述 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

4

1 2 1

1 3 2

3 4 3

2

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。

/*
  二分+倍增+贪心
  ①题目要求使最长时间最短,那我们会想到二分答案,二分出答案之后,
  要使各处的军队尽量向上跑才最优,因为这样能覆盖尽量多的点。
  ②对于能跑到根节点的点,我们就记录他跑到根节点后最多还能跑多远,
  并且记录下他是从根节点的哪那个子节点来的,这些信息都记录到b结构体中。
  ③对于那些跑不到根节点的军队,我们让他待在能跑到的最高处,而且进行一遍深搜,
  如果某个点的所有子节点都保证能覆盖,我们就认为它也能被覆盖。
  ④在根节点的子节点中找到没有被覆盖的,然后用b结构体中的军队来分配给他们,
  分配原则是:如果b结构体军队原来的点没有覆盖,就覆盖原来的,否则,从小到大一一对应。
*/
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#define M 50010
using namespace std;
int head[M],pos[M],fa[M][20],dis[M][20],vis[M],n,m;
struct node{int v,pre,t;};node e[M*2];
struct Node{int u,v;};Node b[M],c[M];
int read()
{
    char c=getchar();int num=0,flag=1;
    while(c<‘0‘||c>‘9‘){if(c==‘-‘)flag=-1;c=getchar();}
    while(c>=‘0‘&&c<=‘9‘){num=num*10+c-‘0‘;c=getchar();}
    return num*flag;
}
void add(int i,int x,int y,int z)
{
    e[i].v=y;
    e[i].t=z;
    e[i].pre=head[x];
    head[x]=i;
}
bool cmp(const Node&x,const Node&y)
{
    return x.v<y.v;
}
void dfs(int now,int from)
{
    fa[now][0]=from;
    for(int i=head[now];i;i=e[i].pre)
      if(e[i].v!=from)
      {
          dis[e[i].v][0]=e[i].t;
          dfs(e[i].v,now);
      }
}
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 color(int x)
{
    bool p=1,q=0;
    for(int i=head[x];i;i=e[i].pre)
      if(e[i].v!=fa[x][0])
      {
          color(e[i].v);p&=vis[e[i].v];q=1;
      }
    if(p&&q&&x!=1)vis[x]=1;
}
bool check(int x)
{
    memset(vis,0,sizeof(vis));
    int cnt=0,tot=0;
    for(int i=1;i<=m;i++)
    {
        int y=pos[i],z=0;
        for(int j=18;j>=0;j--)//尽量向上跑
          if(fa[y][j]&&z+dis[y][j]<=x)
          {
              z+=dis[y][j];
              y=fa[y][j];
          }
        if(y!=1)vis[y]=1;//跑不到根节点
        else//能跑到根节点,求出b结构体
        {
            b[++cnt].v=x-z;
            y=pos[i];
            for(int j=18;j>=0;j--)
              if(fa[y][j]>1)
                y=fa[y][j];
            b[cnt].u=y;
        }
    }
    color(1);//处理跑不到根节点的点
    for(int i=head[1];i;i=e[i].pre)//找根节点的子节点
      if(!vis[e[i].v])
      {
          c[++tot].u=e[i].v;
          c[tot].v=e[i].t;
      }
    sort(b+1,b+cnt+1,cmp);
    sort(c+1,c+tot+1,cmp);
    int j=1;
    for(int i=1;i<=cnt;i++)//匹配
    {
        if(!vis[b[i].u])vis[b[i].u]=1;
        else if(b[i].v>=c[j].v)vis[c[j].u]=1;
        while(vis[c[j].u]&&j<=tot)j++;
    }
    return j>tot;
}
int main()
{
    n=read();
    int ll=0,rr=0;
    for(int i=1;i<n;i++)
    {
        int x=read(),y=read(),z=read();
        add(i*2-1,x,y,z);add(i*2,y,x,z);
        rr+=z;
    }
    m=read();
    for(int i=1;i<=m;i++)
      pos[i]=read();
    dfs(1,1);//深搜记录父亲结点,边权值
    get_fa();//DP求出倍增用到的节点和权值
    while(ll<=rr)//二分答案
    {
        int mid=(ll+rr)/2;
        if(check(mid))rr=mid-1;
        else ll=mid+1;
    }
    if(check(ll))printf("%d",ll);
    else printf("-1");
    return 0;
}

时间: 2024-10-14 10:34:01

疫情控制(codevs 1218)的相关文章

习题:疫情控制(二分+倍增+贪心)

noip2012疫情控制 描述H国有n个城市,这n个城市用n-1条双向道路相互连通构成一棵树,1号城市是首都,也是树中的根节点. H国的首都爆发了一种危害性极高的传染病.当局为了控制疫情,不让疫情扩散到边境城市(叶子节点所表示的城市),决定动用军队在一些城市建立检查点,使得从首都到边境城市的每一条路径上都至少有一个检查点,边境城市也可以建立检查点.但特别要注意的是,首都是不能建立检查点的. 现在,在H国的一些城市中已经驻扎有军队,且一个城市可以驻扎多个军队.一支军队可以在有道路连接的城市间移动,

codevs1218 疫情控制

疫情控制(blockade.cpp/c/pas)[问题描述]H 国有 n 个城市,这 n 个城市用 n-1 条双向道路相互连通构成一棵树,1 号城市是首都,也是树中的根节点.H 国的首都爆发了一种危害性极高的传染病.当局为了控制疫情,不让疫情扩散到边境城市(叶子节点所表示的城市),决定动用军队在一些城市建立检查点,使得从首都到边境城市的每一条路径上都至少有一个检查点,边境城市也可以建立检查点.但特别要注意的是,首都是不能建立检查点的.现在,在 H 国的一些城市中已经驻扎有军队,且一个城市可以驻扎

洛谷P1084 [NOIP2012提高组Day2T3]疫情控制

P1084 疫情控制 题目描述 H 国有 n 个城市,这 n 个城市用 n-1 条双向道路相互连通构成一棵树,1 号城市是首都,也是树中的根节点. H 国的首都爆发了一种危害性极高的传染病.当局为了控制疫情,不让疫情扩散到边境城市(叶子节点所表示的城市),决定动用军队在一些城市建立检查点,使得从 首都到边境城市的每一条路径上都至少有一个检查点,边境城市也可以建立检查点.但特别要注意的是,首都是不能建立检查点的. 现在,在 H 国的一些城市中已经驻扎有军队,且一个城市可以驻扎多个军队.一支军队可以

luoguP1084 疫情控制(题解)(搜索+贪心)

luoguP1084 疫情控制 题目 #include<iostream> #include<cstdlib> #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #define il inline #define rg register #define ll long long #define N 60000 #define inf 21474

[luogu]P1084 疫情控制

原题链接:P1084 疫情控制 题意 给定一棵带权树,$1$号点为根节点,某些点上有军队. 现在要求移动这些军队,使军队覆盖所有的叶子节点,求移动距离最大值的最小值. 分析 很难直接求出最小值,我们可以考虑二分这个最小值,让原问题转化为判定问题. 二分最小值,我们只需要判断能否在$mid$距离内使军队全部移动到覆盖所有的叶子点. 1.上移军队 一个军队往哪个方向移动贡献最大? 明显是往根节点方向移动. 所以很明显我们第一步就是要把所有的节点尽可能地往上移动. 如果移动到顶(处于根节点的儿子节点)

luoguP1084疫情控制

原题地址 题目分析 我们要明确我们做什么,一步一步慢慢来,否则会被这题逼疯. 1.预处理倍增 我们会发现,离根节点越近的节点,控制的节点更多.所以由贪心的思想,所有的军队都要尽可能地往根节点走. ”往上提“类型问题一般使用倍增优化. 好大的,那么我们可以dfs一遍,将倍增要用的一些值都处理好(见代码) 2.二分答案 军队可以同时移动,说明我们要控制传染病的时间是军队移动到位时,移动时间最长的军队的移动时间.而我们要求最小值,即要求最大化最小值. 二分答案一般用于求最大化最小值,最小化最大值. 所

【CodeVS 1218】【NOIP 2012】疫情控制

http://codevs.cn/problem/1218/ 比较显然的倍增,但是对于跨过根需要很多讨论,总体思路是贪心. 写了一上午,不想再说什么了 #include<cstdio> #include<cstring> #include<algorithm> using namespace std; typedef long long ll; const int N = 100003; int in() { int k = 0, fh = 1; char c = ge

codevs 1218 疫情控制

啊好烦这道题.... 基本思路网上都有. 注意的一点是在匹配的时候,如果有军队的来源没有被匹配到,那么就先匹配这个来源.(因为不花钱). 不过数据好水.... #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define maxv 50050 #define maxe 100500 using namespace std; int n,x,y,z,g[max

【noip 2012】提高组Day2T3.疫情控制

Description H国有n个城市,这n个城市用n-1条双向道路相互连通构成一棵树,1号城市是首都,也是树中的根节点. H国的首都爆发了一种危害性极高的传染病.当局为了控制疫情,不让疫情扩散到边境城市(叶子节点所表示的城市),决定动用军队在一些城市建立检查点,使得从首都到边境城市的每一条路径上都至少有一个检查点,边境城市也可以建立检查点.但特别要注意的是,首都是不能建立检查点的. 现在,在H国的一些城市中已经驻扎有军队,且一个城市可以驻扎多个军队.一支军队可以在有道路连接的城市间移动,并在除