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 2147483647
using namespace std;

int n,m,hd[N],cnt,u,v,w;
int c,idx[N];
int le,ri=500000;
int dis[N][20],up[N][20];
int ok[N],use[N],vis[N];
struct S{
    int res,idx;
}ne[N],to[N];
struct T{
    int nt,to,w;
}edge[N<<1];
il void re(rg int &x);
void add(rg int fm,rg int to,rg int w);
void ST(rg int i,rg int fa);
int check(rg int lim);
int Dfs(rg int u,rg int fa);
int Cmp(const S &x,const S &y);

int main()
{
    re(n);
    for(rg int i=1;i<n;++i)
    {
        re(u),re(v),re(w);
        add(u,v,w),add(v,u,w);
        if(u==1||v==1)c++;
    }
    re(m);
    if(m<c){cout<<-1;return 0;}
    for(rg int i=1;i<=m;++i)
        re(idx[i]);

    ST(1,0);
    for(rg int k=1;k<=19;++k)
    {
        for(rg int i=1;i<=n;++i)
        {
            up[i][k]=up[up[i][k-1]][k-1];
            dis[i][k]=dis[up[i][k-1]][k-1]+dis[i][k-1];
        }
    }
    while(le<ri)
    {
        rg int mid=((le+ri)>>1);
        if(check(mid))ri=mid;
        else le=mid+1;
    }
    cout<<le;

    return 0;
}

il void re(rg int &x)
{
    rg int res=0;rg int w=1;char c=getchar();
    while((c<‘0‘||c>‘9‘)&&c!=‘-‘)c=getchar();
    if(c==‘-‘)w=-1,c=getchar();
    while(c>=‘0‘&&c<=‘9‘)res=(res<<3)+(res<<1)+c-‘0‘,c=getchar();
    x=w*res;
}
void add(rg int fm,rg int to,rg int w)
{
    edge[++cnt].nt=hd[fm];
    edge[cnt].to=to;
    edge[cnt].w=w;
    hd[fm]=cnt;
}
void ST(rg int i,rg int fa)
{
    up[i][0]=fa;
    for(rg int k=hd[i];k;k=edge[k].nt)
    {
        rg int qw=edge[k].to;
        if(qw==fa)continue;
        dis[qw][0]=edge[k].w;
        ST(qw,i);
    }
}
int check(rg int lim){
    memset(ok,0,sizeof(ok));
    memset(use,0,sizeof(use));
    memset(vis,0,sizeof(vis));
    rg int cnt1=0,cnt2=0;
    rg int top=1;
    for(rg int i=1;i<=m;++i){
        rg int res=lim,u=idx[i];
        for(rg int k=19;k>=0;--k){
            if(up[u][k]&&up[u][k]!=1&&res>=dis[u][k])
                res-=dis[u][k],u=up[u][k];
        }
        if(up[u][0]==1&&res>dis[u][0])
        {
            to[++cnt1].res=res-dis[u][0];
            to[cnt1].idx=u;
        }
        else ok[u]=1;
    }
    Dfs(1,0);
    for(rg int k=hd[1];k;k=edge[k].nt){
        rg int qw=edge[k].to;
        if(!ok[qw]){
            ne[++cnt2].res=dis[qw][0];
            ne[cnt2].idx=qw;
        }
    }
    sort(to+1,to+cnt1+1,Cmp);
    sort(ne+1,ne+cnt2+1,Cmp);
    if(cnt1<cnt2)return 0;
    for(rg int i=1;i<=cnt1;++i)
    {
        if(!vis[to[i].idx])
        {
            vis[to[i].idx]=1;
            continue;
        }
        while(vis[ne[top].idx])top++;
        if(to[i].res>=ne[top].res)
        {
            vis[ne[top].idx]=1,top++;
            continue;
        }
        if(top>cnt2)break;
    }
    while(vis[ne[top].idx])top++;
    if(top<=cnt2)return 0;
    return 1;
}
int Dfs(rg int u,rg int fa)
{
    rg int temp=1,flag=0;
    for(rg int k=hd[u];k;k=edge[k].nt)
    {
        rg int qw=edge[k].to;
        if(qw==fa)continue;
        flag++,temp&=Dfs(qw,u);
    }
    if(!flag)temp=0;
    ok[u]=(ok[u]|temp);
    if(ok[u]&&up[u][0]==1)
        vis[u]=1;
    return ok[u];
}
int Cmp(const S &x,const S &y){return x.res<y.res;}

原文地址:https://www.cnblogs.com/cjoierljl/p/9074530.html

时间: 2024-08-04 02:23:42

luoguP1084 疫情控制(题解)(搜索+贪心)的相关文章

luoguP1084疫情控制

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

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

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

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

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

codevs1218 疫情控制

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

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

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

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

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

测试赛D - The War(有控制范围的贪心)

D - The War Time Limit:2000MS     Memory Limit:65536KB     64bit IO Format:%lld & %llu Submit Status Description A war had broken out because a sheep from your kingdom ate some grasses which belong to your neighboring kingdom. The counselor of your k

sas高级编程(3)format过程,管理format、永久使用format给指定variable、控制format搜索顺序、fmterr、利用数据集创建format,由format创建数据集、制表过程

/***************************************************格式过程************************************************/ PROC FORMAT <option(s)>; EXCLUDE entry(s); INVALUE <$>name <(informat-option(s))>value-range-set(s); PICTURE name <(format-optio

[luogu]P1084 疫情控制

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