zoukankan      html  css  js  c++  java
  • [APIO2013]道路费用

    [APIO2013]道路费用 

    给一些边确定权值,再找MST,还要最大化,很麻烦

    不妨枚举k中一个子集最终会在MST上,此基础上最大化每个边的权值(显然这样最优)

    暴力:

    2^k枚举S,把S中的边都先加进去。原图所有的边跑kruskal,得到MST

    再对于没有在MST上的边,对(x,y)链上的S中的边有权值限制<=w,链上权值对w取min

    O(2^k*(mlogm+mk^2))

    正解:

    k<=20,每次跑一边全局的MST太不值得了。

    假设Wki=-inf,即把S=全集都加进去,原图所有边跑kruskal,这个时候在MST上的边,一定无论如何都会在MST上了

    不经过这k条边,可以缩点!

    K+1个连通块编号为1~K+1

    这样每次check变成了O(k^3)因为有k^2条原图的边

    显然,这k^2条边不是必须的

    Wki=inf,即直接用这些边跑MST,如果不在MST上的,无论如何都不会在了。并且不会影响S的边的min

    所以,边、点剩下k个

    O(mlogm+2*k*k^2)

    // luogu-judger-enable-o2
    #include<bits/stdc++.h>
    #define reg register int
    #define il inline
    #define fi first
    #define se second
    #define mk(a,b) make_pair(a,b)
    #define numb (ch^'0')
    #define pb push_back
    #define solid const auto &
    #define enter cout<<endl
    using namespace std;
    typedef long long ll;
    template<class T>il void rd(T &x){
        char ch;x=0;bool fl=false;
        while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true);
        for(x=numb;isdigit(ch=getchar());x=x*10+numb);
        (fl==true)&&(x=-x);
    }
    template<class T>il void output(T x){if(x/10)output(x/10);putchar(x%10+'0');}
    template<class T>il void ot(T x){if(x<0) putchar('-'),x=-x;output(x);putchar(' ');}
    template<class T>il void prt(T a[],int st,int nd){for(reg i=st;i<=nd;++i) ot(a[i]);putchar('
    ');}
    
    namespace Miracle{
    const int N=1e5+5;
    const int M=3e5+5;
    const int K=30;
    const int inf=0x3f3f3f3f;
    int n,m,k;
    ll ans;
    struct node{
        int x,y,w;
        bool friend operator <(node a,node b){
            return a.w<b.w;        
        }
    }E[M],t[K],mao[K];
    struct edge{
        int nxt,to;
        int z;
    }e[2*N];
    int hd[N],cnt;
    void add(int x,int y,int z){
        e[++cnt].nxt=hd[x];
        e[cnt].to=y;e[cnt].z=z;
        hd[x]=cnt;
    }
    int be[N];
    int num;
    int tc;
    
    int gf[N];
    int fin(int x){
        return gf[x]==x?x:gf[x]=fin(gf[x]);
    }
    int has[N],tot;
    int fa[N];
    int dep[N];
    ll sum[K],val[K],wei[N];
    int big[K];
    int on[K];
    void dp(int x,int d){
        dep[x]=d;
        sum[x]=val[x];
        for(reg i=hd[x];i;i=e[i].nxt){
            int y=e[i].to;
            if(y==fa[x]) continue;
            fa[y]=x;
            dp(y,d+1);
            sum[x]+=sum[y];
        }
    }
    ll che(){
        if(tot==0) return 0;
        for(reg i=1;i<=num;++i){
            gf[i]=i;
            hd[i]=0;
            big[i]=inf;
        }
        cnt=0;
        for(reg p=1;p<=tot;++p){
            int i=has[p];
            int x=mao[i].x,y=mao[i].y;
            int k1=fin(x),k2=fin(y);
            if(k1!=k2){
                gf[k1]=k2;
                add(x,y,0);add(y,x,0);
            }
        }
        for(reg i=1;i<=tc;++i){
            on[i]=0;
            int x=t[i].x,y=t[i].y;
            int k1=fin(x),k2=fin(y);
            if(k1!=k2){
                gf[k1]=k2;
                on[i]=1;
                add(x,y,0);add(y,x,0);
            }
        }
        fa[1]=0;dep[1]=0;
        dp(1,1);
        for(reg i=1;i<=tc;++i){
            if(!on[i]){
                int x=t[i].x,y=t[i].y;
                if(dep[x]<dep[y]) swap(x,y);
                while(dep[x]>dep[y]) big[x]=min(big[x],t[i].w),x=fa[x];
                while(x!=y){
                    big[x]=min(big[x],t[i].w);
                    big[y]=min(big[y],t[i].w);
                    x=fa[x],y=fa[y];
                }
            }
        }
        ll ret=0;
        for(reg p=1;p<=tot;++p){
            int i=has[p];
            int x=mao[i].x,y=mao[i].y;
            if(dep[x]<dep[y]) swap(x,y);
            ret+=(ll)big[x]*sum[x];
        }
        return ret;
    }
    void dfs(int x){
        if(x==k+1){
            ans=max(ans,che());
            return;
        }
        dfs(x+1);
        has[++tot]=x;
        dfs(x+1);
        has[tot--]=0;
    }
    
    void tarjan(int x){
        be[x]=num;
        val[num]+=wei[x];
        for(reg i=hd[x];i;i=e[i].nxt){
            int y=e[i].to;
            if(be[y]||e[i].z) continue;
            tarjan(y);
        }
    }
    int main(){
        rd(n);rd(m);rd(k);
        for(reg i=1;i<=m;++i){
            rd(E[i].x);rd(E[i].y);rd(E[i].w);
        }
        for(reg i=1;i<=k;++i){
            rd(mao[i].x);rd(mao[i].y);
        }
        for(reg i=1;i<=n;++i){
            rd(wei[i]);
        }
        sort(E+1,E+m+1);
        for(reg i=1;i<=n;++i){
            gf[i]=i;
        }
        for(reg i=1;i<=k;++i){
            int x=mao[i].x,y=mao[i].y;
            int k1=fin(x),k2=fin(y);
            if(k1!=k2){
                gf[k1]=k2;
                add(x,y,1);add(y,x,1);
            }
        }
    
        for(reg i=1;i<=m;++i){
            int x=E[i].x,y=E[i].y;
            int k1=fin(x),k2=fin(y);
            if(k1!=k2){
                gf[k1]=k2;
                add(x,y,0);add(y,x,0);
            }
        }
        for(reg i=1;i<=n;++i){
            if(!be[i]){
                ++num;
                tarjan(i);
            }
        }
        memset(gf,0,sizeof gf);
        for(reg i=1;i<=num;++i){
            gf[i]=i;
        }
        for(reg i=1;i<=m;++i){
            int x=E[i].x,y=E[i].y;
            if(be[x]!=be[y]){
                x=be[x];y=be[y];
                int k1=fin(x),k2=fin(y);
                if(k1!=k2){
                    gf[k1]=k2;
                    ++tc;
                    t[tc].x=x;t[tc].y=y;
                    t[tc].w=E[i].w;
                }
            }
        }
        for(reg i=1;i<=k;++i){
            mao[i].x=be[mao[i].x];
            mao[i].y=be[mao[i].y];
        }
        memset(hd,0,sizeof hd);
        cnt=0;
        dfs(1);
        ot(ans);
        return 0;
    }
    
    }
    signed main(){
        Miracle::main();
        return 0;
    }
    
    /*
       Author: *Miracle*
    */

    k很小,考虑暴力枚举,这样有了方向

    每次MST太亏,考虑化简点、边

    化简边数,找必须边和不可能边类似:[HNOI2010]城市建设

  • 相关阅读:
    Kubernetes 集成研发笔记
    Rust 1.44.0 发布
    Rust 1.43.0 发布
    PAT 甲级 1108 Finding Average (20分)
    PAT 甲级 1107 Social Clusters (30分)(并查集)
    PAT 甲级 1106 Lowest Price in Supply Chain (25分) (bfs)
    PAT 甲级 1105 Spiral Matrix (25分)(螺旋矩阵,简单模拟)
    PAT 甲级 1104 Sum of Number Segments (20分)(有坑,int *int 可能会溢出)
    java 多线程 26 : 线程池
    OpenCV_Python —— (4)形态学操作
  • 原文地址:https://www.cnblogs.com/Miracevin/p/10801012.html
Copyright © 2011-2022 走看看