P1084 疫情控制

题目描述

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

H 国的首都爆发了一种危害性极高的传染病。当局为了控制疫情,不让疫情扩散到边境城市(叶子节点所表示的城市),决定动用军队在一些城市建立检查点,使得从首都到边境城市的每一条路径上都至少有一个检查点,边境城市也可以建立检查点。但特别要注意的是,首都是不能建立检查点的。

现在,在 H 国的一些城市中已经驻扎有军队,且一个城市可以驻扎多个军队。一支军队可以在有道路连接的城市间移动,并在除首都以外的任意一个城市建立检查点,且只能在一个城市建立检查点。一支军队经过一条道路从一个城市移动到另一个城市所需要的时间等于道路的长度(单位:小时)。

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

输入输出格式

输入格式:

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

接下来的 n-1 行,每行 3 个整数,u、v、w,每两个整数之间用一个空格隔开,表示从城市 u 到城市 v 有一条长为 w 的道路。数据保证输入的是一棵树,且根节点编号为 1。

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

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

输出格式:

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

输入输出样例

输入样例#1:

4
1 2 1
1 3 2
3 4 3
2
2 2

输出样例#1:

3

说明

【输入输出样例说明】

第一支军队在 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。

NOIP 2012 提高组 第二天 第三题

题目大意:

一棵树上的某些点上有一个或多个军队 怎样安排在最少的时间内使根节点

到所有叶子节点的路径上都有军队。

题解: 贪心+二分+倍增

woc这个题写了两天了....终于A了....当然看的dalao的代码

题解第一遍写莫名其妙没了...也没保存..吃饭回来写的第二遍...orz

一、

①怎样走最优?不走或者是向根走。深度越浅覆盖的节点越多。

②答案具有单调性,所以我们二分一个时间,那么该问题就变成了一个可行性问题,在限定的时间内能否覆盖。

③何时无法覆盖?当军队数小于根的儿子的个数时,无法覆盖。

二、如何分配军队?

由于我们二分了一个时间,所以我们要让军队在限定时间内尽量向根走。这时所有的军队可以分为两类。

能走到根节点和不能走到根节点的。对于不能走到根的,我们尽量能走多远就走多远,深度尽量的浅,这

样最优。能走到根节点我们需要记录这个军队在我们二分的时间内还能走多远(这样便于之后的军队分配,

也就是一开始感觉很麻烦的一个子树的军队要去根的另一个子树的问题。)及这个军队是从根的哪个子树来

的。并且我们对于某个节点的儿子都被封锁的情况,视为这个点也被封锁,这个操作dfs就好。接下来我们

要分配聚集在根节点的军队。这个分配方法为,用根节点的能走的距离短的去覆盖距离根节点近的,这样更优。

还有两个问题,如果根节点的某个军队它来的那个子树没有被覆盖,先让这个军队去覆盖它来的子树,这样不需要

从别的子树调用军队,更优。并且对于能来到根节点却不能回去的不能用它覆盖。

三、代码实现

①统计军队数量和根的儿子个数,如果军队数量小于根节点的儿子个数,一定不能覆盖。

②dfs倍增预处理以及被封锁的节点的处理。

③二分时间。

④结构体记录根节点军队的信息

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define maxn 50005
#define LL long long
using namespace std;

int n,sumedge,js,cc,cnt,m;
int head[maxn],dad[maxn][22],g[maxn][22],root[maxn],a[maxn],has[maxn];
LL ans,l,r,mid;
LL ecnt,inf;
struct B{
    int root;LL rest;
}b[maxn];

struct C{
    int pos;LL dis;
}c[maxn];

struct Edge{
    int x,y,z,nxt;
    Edge(int x=0,int y=0,int z=0,int nxt=0):
        x(x),y(y),z(z),nxt(nxt){}
}edge[maxn<<1];

void add(int x,int y ,int z){
    edge[++sumedge]=Edge(x,y,z,head[x]);
    head[x]=sumedge;
}

bool cmpb(B a ,B b){
    return a.rest<b.rest;
}

bool cmpc(C a,C b){
    return a.dis<b.dis;
}

inline int read(){
    int x=0,f=1;char ch=getchar();
    for(;!isdigit(ch);ch=getchar())if(ch==‘-‘)f=-1;
    for(;isdigit(ch);ch=getchar())x=x*10+ch-‘0‘;
    return x*f;
}

void dfs(int x){
    for(int i=head[x];i;i=edge[i].nxt){
        int v=edge[i].y;
        if(v==dad[x][0])continue;
        dad[v][0]=x;g[v][0]=edge[i].z;
        if(x==1)root[v]=v;else root[v]=root[x];
        dfs(v);
    }
}

void dfs_(int x){
    bool flag=false,all=true;
    for(int i=head[x];i;i=edge[i].nxt){
        int v=edge[i].y;
        if(v==dad[x][0])continue;
        flag=true;if(!has[v])all=false;
        dfs_(v);
    }
    if(flag&&all&&x!=1)has[x]=1;
}

bool check(LL lim){
    memset(has,0,sizeof(has));
    memset(b,0,sizeof(b));
    memset(c,0,sizeof(c));
    cnt=js=0;
    for(int i=1;i<=m;i++){
        int u=a[i];LL tot=lim;
        for(int j=16;j>=0;j--){
            if(g[u][j]<=tot&&dad[u][j]!=0){
                tot-=g[u][j];
                u=dad[u][j];
            }
        }
        if(u==1){
            b[++cnt].rest=tot;
            b[cnt].root=root[a[i]];
        }else has[u]=1;
    }
    dfs_(1);
    for(int i=head[1];i;i=edge[i].nxt){
        int v=edge[i].y;
        if(has[v])continue;
        c[++js].pos=v;c[js].dis=edge[i].z;
    }
    if(js>cnt)return false;
    sort(b+1,b+cnt+1,cmpb);
    sort(c+1,c+js+1,cmpc);
    c[js+1].dis=0x7fffffff;
    int now=1;
    for(int i=1;i<=cnt;i++){
        if(has[b[i].root]==0)has[b[i].root]=1;
        else{
            while(has[c[now].pos])now++;
            if(b[i].rest>=c[now].dis)has[c[now++].pos]=1;
        }
        while(has[c[now].pos])now++;
    }
    return now>js;
}

void slove(){
    dfs(1);
    for(int j=1;j<=18;j++)
     for(int i=1;i<=n;i++)
      dad[i][j]=dad[dad[i][j-1]][j-1],
      g[i][j]=g[i][j-1]+g[dad[i][j-1]][j-1];
    l=0; r=500000;
    if(!check(r)) { printf("-1"); return ; }
    while(l<=r){
        mid=(l+r)>>1;
        if(check(mid))ans=mid,r=mid-1;
        else l=mid+1;
    }
}

int main(){
    n=read();
    for(int i=1;i<n;i++){
        int x,y,z;
        x=read();y=read();z=read();
        add(x,y,z);add(y,x,z);
        if(x==1||y==1)cc++;
    }
    m=read();
    for(int i=1;i<=m;i++)a[i]=read();
    if(cc>m){printf("-1\n");return 0;}
    slove();
    cout<<ans<<endl;
    return 0;
}

 

时间: 2024-07-30 02:15:45

P1084 疫情控制的相关文章

[luogu]P1084 疫情控制

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

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

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

洛谷 P1084 疫情控制 【二分+数据结构】

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

洛谷P1084 疫情控制

题目:https://www.luogu.org/problemnew/show/P1084 这道题由于洛谷数据有点水,如果有vijos的推荐去vijos交一下,他的数据还好. vijos:https://vijos.org/p/1783 题目描述 H 国有 n 个城市,这 n 个城市用 n-1 条双向道路相互连通构成一棵树,1 号城市是首都,也是树中的根节点. H 国的首都爆发了一种危害性极高的传染病.当局为了控制疫情,不让疫情扩散到边境城市(叶子节点所表示的城市),决定动用军队在一些城市建立

NOIP2012 洛谷P1084 疫情控制

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

Luogu P1084 疫情控制 | 二分答案 贪心

题目链接 观察题目,答案明显具有单调性. 因为如果用$x$小时能够控制疫情,那么用$(x+1)$小时也一定能控制疫情. 由此想到二分答案,将问题转换为判断用$x$小时是否能控制疫情. 对于那些在$x$小时内不能够走到根节点的子节点上的军队,让他们尽量往上走即可,走到哪里是哪里,这样显然不会更劣. 对于那些在$x$小时内能走到根节点的子节点上的军队,就让他们先走到根节点的子节点上. 然后搞搞贪心即可. #include<iostream> #include<cstdio> #incl

luogu P1084疫情控制 二分

链接 luogu 思路 二分. 每个军队在一定的时间内越往上越好. 注意一个军队可以跨过1去帮别的. 把能到1脚下的点都存下来特判. 有一种情况是这个子树内只有一个军队,但这个军队跑去帮别人了. 其他军队来帮这个子树. 就像这样. 四号点的军队还有2秒钟,而且四号点有两个军队. 2号点有一个军队,还有101秒钟. 三号点没有军队. 四号点的一个军队到2,二号点的的军队到三. 这样的2号点放弃内部去外部的条件是什么? 答案是两倍的边权<剩余时间. 不然的话,四号店可以直接去拯救三号点了. 代码 #

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

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

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

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