zoukankan      html  css  js  c++  java
  • 洛谷P1084 疫情控制(NOIP2012)(二分答案,贪心,树形DP)

    洛谷题目传送门

    费了几个小时杠掉此题,如果不是那水水的数据的话,跟列队的难度真的是有得一比。。。

    话说蒟蒻仔细翻了所有的题解,发现巨佬写的都是倍增,复杂度是(O(nlog nlog nw))的,貌似还不够优秀。

    其实我们与其对于每一个点都通过倍增向上找到对应位置,还不如直接从上到下dfs一遍,判断:如果当前点子树内初始位置最浅的军队与当前点距离不超过(mid),或者所有子树都被封锁,那么当前点也被封锁。

    这样以后再二分,时间复杂度降至(O(nlog nw))。其它部分的思路Dalao们的题解里都讲清楚了,蒟蒻也不多说了qwq

    #include<bits/stdc++.h>
    #define LL long long
    #define RG register
    #define R RG int
    using namespace std;
    const int N=5e4+9,M=1e5+9;
    int p,he[N],ne[M],to[M],w[M],top[N],at[N],t[N],mn[N];
    LL mid,d[N],dis[N];
    bool cov[N],use[N];
    inline bool cmp(R x,R y){
        return d[x]>d[y];
    }
    void dp(R x,R f){
        top[x]=p;
        if(mid<d[x])mid=d[x];//控制二分上界
        if(to[he[x]]==f)he[x]=ne[he[x]];//悄悄把反边删掉
        for(R i=he[x];i;i=ne[i]){
            if(to[ne[i]]==f)ne[i]=ne[ne[i]];
            d[to[i]]=d[x]+w[i];
            dp(to[i],x);
        }
    }
    void dfs(R x){
        if(cov[x]){dis[x]=0;return;}
        dis[x]=1ll<<60;
        if(!(cov[x]=he[x]))return;//到达叶子节点还没有被封锁
        for(R y,i=he[x];i;i=ne[i]){
            dfs(y=to[i]);
            cov[x]&=cov[y];
            dis[x]=min(dis[x],dis[y]+w[i]);
        }
        if(dis[x]<=mid)cov[x]=1;//子树内军队能够赶到
    }
    int main(){
        R n,m,cnt=0,i,u,v;
        cin>>n;
        for(i=1;i<n;++i){
            cin>>u>>v>>w[++p];w[p+1]=w[p];
            ne[p]=he[u];to[he[u]=p]=v;++p;
            ne[p]=he[v];to[he[v]=p]=u;
        }
        for(i=he[1];i;i=ne[i])
            d[p=to[i]]=w[i],dp(t[++cnt]=to[i],1);
        cin>>m;
        if(cnt>m)return cout<<"-1"<<endl,0;//无解
        for(i=1;i<=m;++i)cin>>at[i];
        sort(t+1,t+cnt+1,cmp);//排序,方便接下来贪心
        sort(at+1,at+m+1,cmp);
        RG LL l=0,r=mid+d[t[1]];
        while(l<r){
            mid=(l+r)>>1;
            memset(cov,0,n+1);
            memset(use,0,n+1);
            for(i=1;i<=cnt;++i)mn[t[i]]=0;//清空
            for(i=1;d[at[i]]>mid;++i)
                cov[at[i]]=1;//到不了根节点,直接留在子树内
            for(p=i;i<=m;++i)
                if(!mn[top[at[i]]])mn[top[at[i]]]=i;
                //每个子树预留一个贡献最小的军队
            use[0]=1;u=m+1;
            for(i=1;i<=cnt;++i){
                dfs(t[i]);
                if(cov[t[i]])continue;
                if(use[mn[t[i]]]){//预留已用,只好拿其它子树的
                    for(--u;u>=p&&(d[at[u]]+d[t[i]]>mid||use[u]);--u);
                    if(u<p)break;
                    use[u]=1;
                }
                else use[mn[t[i]]]=1;//预留直接用
            }
            u>=p?r=mid:l=mid+1;
        }
        cout<<l<<endl;
        return 0;
    }
    
  • 相关阅读:
    JID 2.0 RC4 发布,高性能的 Java 序列化库
    FBReaderJ 1.6.3 发布,Android 电子书阅读器
    Arquillian 1.0.3.Final 发布,单元测试框架
    JavaScript 的宏扩展 Sweet.js
    Hypertable 0.9.6.5 发布,分布式数据库
    JRuby 1.7.0 发布,默认使用 Ruby 1.9 模式
    httppp 1.4.0 发布,HTTP响应时间监控
    Redis 2.6.0 正式版发布,高性能K/V服务器
    OfficeFloor 2.5.0 发布,IoC 框架
    XWiki 4.3 首个里程碑发布
  • 原文地址:https://www.cnblogs.com/flashhu/p/9704153.html
Copyright © 2011-2022 走看看