zoukankan      html  css  js  c++  java
  • 非严格/严格次小生成树问题

    转载自新博客:https://acxblog.site/archives/smst-problem.html

    Problem

    BZOJ 入门OJ P1634
    Luogu P4180 BJWC 次小生成树

    Introduction

    首先讲非严格次小生成树的做法。

    先建立权值之和为(W)的最小生成树。接着枚举没有被并入到MST的边(u,v)(我们将把这条边加入到MST中,并在原MST中删去一条最大边,使新ST仍然联通),权值为(W_e)。查询树上u->v的路径,在路径选取一个边权最大值(W_m)。则当前枚举的答案为(W-W_m+W_e)。枚举所有的边之后,取最小值即可。

    基本无需证明。这个代码就不给了,可以用倍增和树剖等实现。

    接下来讲解严格次小生成树的做法。

    原方法是枚举一条边(W_e),之后再寻找一条MST上的合法最大边(即在路径上)(W_m)。显然(W_e geq W_m),因此可能由此得到的次小生成树并非严格。所以我们可以再查找路径上的严格次小值(W_{m2}),则显然(W_e > W_{m2}),所以由此得到的生成树一定严格小于MST。同样枚举所有的边,取最小值即可。

    顺便一提,我这题错的地方忘记加了这个,跳点的倍增数组:

    gup[i][j]=gup[gup[i][j-1]][j-1];
    

    MMP

    以及,两种算法的时间复杂度皆为:(O(m logn))

    补充:合并严格最大值和次大值

    假设合并的两对最大值/次大值分别为(m_1,s_1,m_2,s_2),新的最大值/次大值为(m,s)

    我们可以证明,(m)一定会在(m_1,m_2)决出,则直接在两个里取个最大值就行。

    然后(s)首先在(s_1,s_2)取最大值,若(m_1)不等于(m_2),再与(min(m_1,m_2))进行比对。

    Code

    // Code by ajcxsu
    // Problem: Second Minium Spanning Tree
    
    #include<bits/stdc++.h>
    using namespace std;
    
    typedef long long ll;
    const int N=1e6+10, M=3e6+10;
    struct Edge {
        int u,v;
        ll w;
        bool operator < (const Edge &b) { return w<b.w; }
    } e[M];
    bool S[M]; // 标记MST
    int h[N],to[M],nexp[M];
    ll W[M];
    int p=1;
    inline void ins(int a, int b, int w) {
        nexp[p]=h[a], h[a]=p, to[p]=b, W[p]=w, p++;
    }
    
    int fa[N];
    int Find(int x) {
        if(!fa[x]) return x;
        return fa[x]=Find(fa[x]);
    }
    bool Union(int a, int b) {
        int af=Find(a), bf=Find(b);
        if(af==bf) return false;
        fa[af]=bf;
        return true;
    }
    
    const int OP=20;
    int dep[N], gup[N][OP], ma[N][OP], sma[N][OP];
    void dfs(int x, int k) {
        dep[x]=k;
        for(int u=h[x];u;u=nexp[u])
            if(!dep[to[u]]) {
                gup[to[u]][0]=x;
                ma[to[u]][0]=W[u];
                sma[to[u]][0]=-1;
                dfs(to[u], k+1);
            }
    }
    
    ll m1,m2;
    inline void upd(ll x) {
        if(x>m1) m2=m1, m1=x; // m1的值一定要移到m2
        else if(x<m1 && x>m2) m2=x;
    }
    void lca(int a,int b) {
        m1=m2=0;
        if(dep[a]<dep[b]) swap(a,b);
        for(int j=OP-1;j>=0;j--)
            if(dep[gup[a][j]]>=dep[b]) upd(ma[a][j]), upd(sma[a][j]), a=gup[a][j];
        if(a==b) return;
        for(int j=OP-1;j>=0;j--)
            if(gup[a][j]!=gup[b][j]) {
                upd(ma[a][j]), upd(sma[a][j]);
                upd(ma[b][j]), upd(sma[b][j]);
                a=gup[a][j], b=gup[b][j];
            }
        int j=0;
        upd(ma[a][j]), upd(sma[a][j]);
        upd(ma[b][j]), upd(sma[b][j]);
    }
    
    template <typename T> void gn(T &x) {
        x=0;
        char ch=getchar();
        while(ch<'0' || ch>'9') ch=getchar();
        while(ch>='0' && ch<='9') x=x*10+ch-'0', ch=getchar();
    }
    
    int main() {
        int n,m;
        gn(n), gn(m);
        for(int i=0;i<m;i++)
            gn(e[i].u), gn(e[i].v), gn(e[i].w);
        sort(e,e+m);
        ll mst=0;
        for(int i=0, cnt=0;i<m && cnt!=n-1;i++) {
            if(Union(e[i].u, e[i].v)) {
                S[i]=1, mst+=e[i].w;
                ins(e[i].u, e[i].v, e[i].w), ins(e[i].v, e[i].u, e[i].w);
                cnt++;
            }
        }
        dfs(1,1);
        int a[4],ee,ff;
        for(int j=1;j<OP;j++)
            for(int i=1;i<=n;i++) {
                gup[i][j]=gup[gup[i][j-1]][j-1];
                a[0]=ma[i][j-1], a[1]=ma[gup[i][j-1]][j-1];
                a[2]=sma[i][j-1], a[3]=sma[gup[i][j-1]][j-1];
                ee=max(a[0],a[1]), ff=max(a[2],a[3]);
                if(a[0]!=a[1]) ff=max(ff, min(a[0],a[1]));
                ma[i][j]=ee, sma[i][j]=ff;
            }
    
        ll ans=0x7ffffffffffffll;
        for(int i=0;i<m;i++)
            if(!S[i]) {
                lca(e[i].u, e[i].v);
                if(m1!=e[i].w) ans=min(ans, -m1+e[i].w);
                else ans=min(ans, -m2+e[i].w);
            }
        printf("%lld
    ",mst+ans);
        return 0;
    }
    
  • 相关阅读:
    ARM汇编伪指令介绍.
    初识KITL
    c面试题
    Windows ce的体系结构和功能
    c宏定义的技巧总结
    Build in Windows Mobile
    关于wince注册表
    动态链接库(Dynamic Link Library)学习笔记
    WinCE驱动开发问题精华集锦
    OAL之系统时钟
  • 原文地址:https://www.cnblogs.com/acxblog/p/8947292.html
Copyright © 2011-2022 走看看