zoukankan      html  css  js  c++  java
  • 严格次小生成树

    1555:【例 4】次小生成树

     这次是在图里面求严格次小生成树

    #include<iostream>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<stack>
    #include<cstdio>
    #include<queue>
    #include<map>
    #include<vector>
    #include<set>
    using namespace std;
    const int maxn=1e5+10;
    const int M=3e5+10;
    const int INF=0x3fffffff;
    typedef long long LL;
    typedef unsigned long long ull;
    /*
    https://blog.csdn.net/regina8023/article/details/44814899
    https://blog.csdn.net/YYHS_WSF/article/details/82842355
    求出最小生成树,枚举每一条非树边,用它取代掉环上最大的边最优。
    那么相当于求两点到lca的最大边权,直接倍增做。
    但是要注意是严格最小生成树,那么这条非树边与环上最大边相同时可能取代掉的是环上的次大边,那么倍增的时候多维护一个严格次大的边即可。
    */
    int n,m;
    struct node{
        int u,v,wei;
    }ed[M];
    queue<int> q;
    struct edge{
        int to,next,w;
    }e[M*2];
    struct ma{
        int a,b;  //分别是 最大、次大
    }g[maxn][21],p;
    int head[maxn],dep[maxn],f[maxn][21],fa[maxn];  //后两个:深度,倍增数组
    int vis[M];
    bool cmp(node a,node b){
        return a.wei<b.wei;
    }
     
    int findd(int x){
        if(x==fa[x]) return x;
        else return fa[x]=findd(fa[x]);
    }
    LL mst=0;
    void  kru(){
        sort(ed+1,ed+1+m,cmp);
        int cnt=1;
        for(int i=1;i<=m;i++){
            int fa1=findd(ed[i].u);
            int fa2=findd(ed[i].v);
            if(fa1!=fa2){
                cnt++;
                vis[i]=1;
                mst+=ed[i].wei;
                fa[fa1]=fa2;
            }
        }
    }
    int tot;
    void adde(int x,int y,int z){
        e[++tot].to=y;
        e[tot].next=head[x];
        e[tot].w=z;
        head[x]=tot;
        e[++tot].to=x;
        e[tot].next=head[y];
        e[tot].w=z;
        head[y]=tot;
    }
     
    void build(){
        for(int i=1;i<=m;i++){
            if(vis[i]) adde(ed[i].u,ed[i].v,ed[i].wei);  //建立树边
        }
        g[1][0].a=g[1][1].b=-INF; //最小值
        f[1][0]=0;  //根的爸爸
        dep[1]=1;
        q.push(1);
        while(!q.empty()){
            int x=q.front();
            q.pop();
            for(int i=head[x];i;i=e[i].next){
                int y=e[i].to;
                if(y==f[x][0]) continue;  //是爸爸
                f[y][0]=x;
                dep[y]=dep[x]+1;
                g[y][0].a=e[i].w;  //最大值的初值
                q.push(y);
            }
        }
    }
     
    void updat(ma &x,ma y){ ///用y来更新x
        if(x.a>y.a) x.b=max(y.a,x.b);   //b记录的是次大  ,这三行都是在更新次大
        else if(x.a<y.a) x.b=max(x.a,y.b);
        else x.b=max(x.b,y.b);
        x.a=max(x.a,y.a);  //最大直接更新
    }
     
    void ST(){
        for(int j=1;(1<<j)<=n;j++){
            for(int i=1;i<=n;i++){
                f[i][j]=f[f[i][j-1]][j-1];
                updat(g[i][j],g[i][j-1]);
                updat(g[i][j],g[f[i][j-1]][j-1]);
            }
        }
    } 
    void mov(int &x,int deep){  //先移动到同一层
        for(int i=20;i>=0;i--){
            if(dep[f[x][i]]>=deep) {
                updat(p,g[x][i]);
                x=f[x][i];
            }
        }
    }
    void getlca(int x,int y){
        p.a=p.b=-INF;
        if(dep[x]>dep[y]) swap(x,y);
        mov(y,dep[x]);  //先移动到同一层
        if(x==y) return;
        for(int i=20;i>=0;i--){
            if(f[x][i]!=f[y][i]){
                updat(p,g[x][i]);
                updat(p,g[y][i]);   //找到替换的那条边严格最大边
                x=f[x][i];
                y=f[y][i];
            }
        }
        updat(p,g[x][0]);
        updat(p,g[y][0]);
         
    }
    int main(){
        scanf("%d %d",&n,&m);
        for(int i=1;i<=m;i++){
            scanf("%d %d %d",&ed[i].u,&ed[i].v,&ed[i].wei);
        }
        for(int i=1;i<=n;i++) fa[i]=i;
        kru();  //先求出最小生成树的权值
        build();   //用非树边去更新倍增数组,g[][].a  g[][].b
        ST();
        LL ans=(LL)1e15;    //这个要设置的足够大
        for(int i=1;i<=m;i++){
            if(!vis[i]){   //用非树边建立
                getlca(ed[i].u,ed[i].v);
                if(p.a==ed[i].wei){  //最大便与其相等
                    ans=min(ans,mst+ed[i].wei-p.b);
                }
                else ans=min(ans,mst+ed[i].wei-p.a);
            }
        }
        printf("%lld
    ",ans);
    return 0;
    }
    

      

  • 相关阅读:
    js的内置对象arguments
    typeof
    JS 数组赋值,引用传递 问题
    技术突围打造创新解决方案 思岚科技让机器人移动更智能
    2020思岚科技第四季度大事记
    校企合作 | 上海交通大学 X 思岚科技“智能感知创新实验室”正式揭牌
    新基建下的智慧货架机器人,已迎来“下半场”应用期
    2020思岚科技第二季度大事记
    思岚科技2020第一季度大事记
    思岚科技2019第四季度大事件
  • 原文地址:https://www.cnblogs.com/shirlybaby/p/13703198.html
Copyright © 2011-2022 走看看