zoukankan      html  css  js  c++  java
  • 【NOIP】提高组2012 疫情控制

    【题意】n个点的树,1为根,要求删除一些点使得截断根节点和所有叶子结点的路径(不能删根,可以删叶子)。有m支军队在m个点上,每时刻所有军队可以走一步,最终走到的地方就是删除的点,求最短时间。

    【算法】二分,贪心,倍增

    【题解】

    所有点同时走路,求最短时间,这样的询问通常考虑二分转化为判定性问题。(实际上,这题用二分确实没有想到,如果能想到二分整道题就好写一些了)

    容易发现,每支军队贪心地往上走最优。

    那么对于二分的时间,有一部分军队可以到达根,A数组记录这些军队到达根后的剩余时间,待会可以走到第二层覆盖其它节点。

    有一部分军队不能到达根,处理出这些军队能覆盖多少二层节点,B数组不能覆盖的二层节点到根的路径。

    AB各自排序之后,对应匹配,若A能将B全部匹配就可以满足要求,否则不能。

    还有一个问题,一个军队虽然不能到达根后返回来覆盖自己,但可以直接不去根。解决方法是从小到大枚举A时,如果该点本身的二层节点还没覆盖就直接覆盖(因为该点本来就是最劣的,只要能覆盖一个二层结点就不亏)。

    最后的问题是处理出不能到达根的军队能覆盖多少二层结点?可以对每个军队倍增,也可以直接一遍dfs。

    dfs的具体做法是:c[x]表示x被覆盖,t[x]表示x子树的军队到x的最大剩余时间。c[x] = c[son[x]]=1 || t[x]>=0。son[x]表示x的所有儿子。

    #include<cstdio>
    #include<cstring>
    #include<cctype>
    #include<algorithm>
    #define ll long long
    using namespace std;
    int read(){
        char c;int s=0,t=1;
        while(!isdigit(c=getchar()))if(c=='-')t=-1;
        do{s=s*10+c-'0';}while(isdigit(c=getchar()));
        return s*t;
    }
    const int maxn=100010;
    int n,m,tot,first[maxn],top[maxn],a[maxn];
    ll dis[maxn],t[maxn];
    bool b[maxn],c[maxn];
    struct edge{int v,w,from;}e[maxn*2];
    void insert(int u,int v,int w){tot++;e[tot].v=v;e[tot].w=w;e[tot].from=first[u];first[u]=tot;}
    void DFS(int x,int fa,int tp){
        top[x]=tp;
        for(int i=first[x];i;i=e[i].from)if(e[i].v!=fa){
            dis[e[i].v]=dis[x]+e[i].w;//yu ju shun xu
            DFS(e[i].v,x,tp);
        }
    }
    void dfs(int x,int fa){
        c[x]=0;
        for(int i=first[x];i;i=e[i].from)if(e[i].v!=fa){c[x]=1;break;}
        for(int i=first[x];i;i=e[i].from)if(e[i].v!=fa){
            dfs(e[i].v,x);
            c[x]&=c[e[i].v];
            t[x]=max(t[x],t[e[i].v]-e[i].w);
        }
        if(t[x]>=0)c[x]=1;
    }
    int totA,totB;
    struct cyc{ll num;int id;}A[maxn],B[maxn];//
    bool cmp(cyc a,cyc b){return a.num<b.num;}
    bool check(ll time){
        memset(t,-1,sizeof(t));
        totA=0;totB=0;
        for(int i=1;i<=m;i++)if(dis[a[i]]<=time)b[i]=1,A[++totA].num=time-dis[a[i]],A[totA].id=top[a[i]];
            else b[i]=0,t[a[i]]=time;
        dfs(1,0);
        for(int i=first[1];i;i=e[i].from)if(!c[e[i].v])B[++totB].num=e[i].w,B[totB].id=e[i].v;
        sort(A+1,A+totA+1,cmp);sort(B+1,B+totB+1,cmp);
        int now=1;
        for(int i=1;i<=totA;i++){
            while(now<=totB&&c[B[now].id])now++;
            if(!c[A[i].id]){c[A[i].id]=1;continue;}
            if(now<=totB&&A[i].num>=B[now].num){c[B[now++].id]=1;}
        }
        while(now<=totB&&c[B[now].id])now++;//
        if(now>=totB+1)return 1;
        return 0;
    }    
    int main(){
        n=read();
        for(int i=1;i<n;i++){
            int u=read(),v=read(),w=read();
            insert(u,v,w);insert(v,u,w);
        }
        memset(dis,0,sizeof(dis));
        for(int i=first[1];i;i=e[i].from)dis[e[i].v]=e[i].w,DFS(e[i].v,1,e[i].v);
        m=read();
        for(int i=1;i<=m;i++)a[i]=read();
        ll l=0,r=1ll*n*1e9+1,mid;
        while(l<r){
            mid=(l+r)>>1;
            if(check(mid))r=mid;else l=mid+1;
        }
        if(r>1ll*n*1e9)printf("-1");else printf("%lld",l);
        return 0;
    }
    View Code
  • 相关阅读:
    编译型语言和解释性语言
    2.变量和基本类型——2.2变量
    2.变量和基本类型——2.1基本内置类型
    1.开始
    机器学习基础—集成学习Bagging 和 Boosting
    C++多态?
    python dataframe数据条件筛选
    UDA机器学习基础—评估指标
    MFC 树形控件
    MFC 列表控件List Control
  • 原文地址:https://www.cnblogs.com/onioncyc/p/7794735.html
Copyright © 2011-2022 走看看