【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);
}
时间: 2024-10-12 19:07:00

【NOIP2012】 疫情控制的相关文章

NOIP2012 疫情控制

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

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

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

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

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

codevs1218 疫情控制

疫情控制(blockade.cpp/c/pas)[问题描述]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.二分答案 军队可以同时移动,说明我们要控制传染病的时间是军队移动到位时,移动时间最长的军队的移动时间.而我们要求最小值,即要求最大化最小值. 二分答案一般用于求最大化最小值,最小化最大值. 所

刷题总结——疫情控制(NOIP2012提高组)

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

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

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