• 次小生成树


    次小生成树

    题意理解
    要你构造一棵nn个节点的严格次小生成树.

    算法解析
    分析条件
    题目中给出的关键点,就是严格和次小.

    什么是严格
    就是题目强制要求严格单调性,不可以有=号的出现.

    什么是次小
    我们应该都知道,最小生成树,它要求边集合的边总和最小,那么次小生成树,要求边集合的边总和只比最小生成树边集合权值大.

    总结性质
    有至少一个(严格)次小生成树,和最小生成树之间只有一条边的差异

    总而言之,言而总之,我们现在知道了这条多余边的加入.,一定会产生非最小生成树.

    我们不妨令
    ans=最小生成树边权之和

    假如说我们将多余边,替换掉最大权值边.
    Val1==>z此时我们发现当前生成树

    W=ans+z−Val1

    W=最小生成边权之和+加上多余边−最大权值边

    这一轮替换,我们可以认为这棵生成树有潜力成为次小生成树.

    然后,我们发现,换一换次大边,也是可以的.

    我们将多余边,强行替换掉次大权值边.
    Val2==>z此时当前生成树

    W=ans+z−Val2

    W=最小生成树之和+加入多余边−次大权值边

    现在所有的候选生成树都出来了,但是我们面临一个非常严重的问题.

    我们如何快速计算,一条路径上的最大边,和次大边.

    动态规划
    我们可以当前需要知道的状态,无非就是两个.

    一条路径上的最大边
    一条路径上的严格次大边
    所以说,我们不妨就按照倍增数组的思路,去制造两个新数组.

    最大边数组
    严格次大边数组
    f[x][k]=f[fa[x][k−1]][k−1]
    f[x][k]=f[fa[x][k−1]][k−1]
    这是我们非常熟悉的Lca倍增数组.

    然后咱们现在其实,手上掌握的最有力的性质,就是最值性质.

    我们假设一条路径是由三段构造而成.

    是三段,不是就三个点.
    a=>c,c=>b,b=>a
    a=>c,c=>b,b=>a


    我们发现
    A=>B的最大值其实等于max(A=>C最大值,B=>C最大值)

    这就是区间最值性质.

    不过严格次大边,就比较麻烦了,不慌,咱们慢慢画图来.

    为了下面简述方面,我们设置一下变量.
    A=>C上最大边权为ValA,C 次大边权为VA,C

    C=>B上最大边权为ValB,C 次大边权为VB,C

    A=>B上最大边权为ValA,B次大边权为VA,B

    巧计一下,Val字母多,所以是最大边权,V字母少,所以是次大边权.

    我们分类讨论一下,三种情况.

    ①第一段最大值=第二段最大值
    ValA,C=ValB,C

    我们发现两段居然最大值一样.

    次大边权就只能
    VA,B=max(VA,C,VB,C)

    ②第一段最大值<第二段最大值.

    那么此时,次大边权是可以取第一段最大值.

    因为此时总段的最大值,一定是第二段最大值.
    ValA,B=ValB,C因此VA,B可以=ValA,C

    综上所述,我们总结下来就是.
    VA,B=max(ValA,C,VB,C)

    ③第一段最大值>第二段最大值.

    那么此时,次大边权是可以取第二段最大值.

    因为此时总段的最大值,一定是第一段最大值.
    ValA,B=ValA,C因此VA,B可以=ValB,C

    同样,总结一下.
    VA,B=max(ValB,C,vA,B)

    然后我们将A,B,C具体化一下.

    A其实就是起始节点.

    C其实就是A跳跃了2^(i−1)格节点.

    B其实就是A跳跃了2^i格节点.

    #include <bits/stdc++.h>
    using namespace std;
    
    typedef long long ll;
    
    const int maxn=1e5+10;
    const ll inf=0x3f3f3f3f;
    
    int n,m,fa[maxn],val1,val2,dp[3][maxn][20],t,head[maxn],f[maxn][20],deep[maxn];
    ll ans,ans_max;
    struct edge1 {
        int v, next,w;
    }e[maxn*2];
    struct edge2 {
        int u, v, w, vis;
    
        bool operator<(const edge2 &b) const {
            return w < b.w;
        }
    }a[maxn*3];
    
    void add(int u,int v,int w) {
        t++;
        e[t].v = v;
        e[t].w = w;
        e[t].next = head[u];
        head[u] = t;
    }
    
    int fin(int x){
        return x==fa[x]?x:fa[x]=fin(fa[x]);
    }
    void Kruskal() {
        sort(a + 1, a + m + 1);
        for (int i = 1; i <= m; i++) {
            int u = fin(a[i].u);
            int v = fin(a[i].v);
            if (u == v) continue;
            fa[u] = v;
            a[i].vis = 1;
            ans += 1ll*a[i].w;
            add(a[i].u, a[i].v, a[i].w);
            add(a[i].v, a[i].u, a[i].w);
        }
    }
    
    void dfs(int u,int fa) {
    
        for (int i = 1; (1 << i) <= deep[u]; i++) {
            f[u][i] = f[f[u][i - 1]][i - 1];
    
            dp[0][u][i] = max(dp[0][u][i - 1], dp[0][f[u][i - 1]][i - 1]);
            if (dp[0][u][i - 1] != dp[0][f[u][i - 1]][i - 1]) {
                dp[1][u][i] = min(dp[0][u][i - 1], dp[0][f[u][i - 1]][i - 1]);
                dp[1][u][i] = max(dp[1][u][i], dp[1][u][i - 1]);
                dp[1][u][i] = max(dp[1][u][i], dp[1][f[u][i - 1]][i - 1]);
            }
            else
                dp[1][u][i] = max(dp[1][u][i - 1], dp[1][f[u][i - 1]][i - 1]);
        }
    
        for (int i = head[u]; i; i = e[i].next) {
            int v = e[i].v;
            if (v == fa) continue;
            f[v][0] = u;
            dp[0][v][0] = e[i].w;
            dp[1][v][0] = -inf;
            deep[v] = deep[u] + 1;
            dfs(v, u);
        }
    }
    
    void update2(int x) {
        if (x > val1) {
            val2 = val1;
            val1 = x;
        } else if (x > val2 && x != val1)
            val2 = x;
    }
    
    void update(int x,int i) {
        update2(dp[0][x][i]);
        update2(dp[1][x][i]);
    }
    
    void lca(int x,int y) {
        val1 = val2 = -inf;
        if (deep[x] < deep[y]) {
            swap(x, y);
        }
        int h = deep[x] - deep[y], k = 0;
        while (h) {
    
            if (h & 1) {
                update(x,k);
                x = f[x][k];
            }
            h >>= 1;
            k++;
        }
        if (x == y) return;
        for (int k = 19; k >= 0; k--) {
            if (f[x][k] != f[y][k]) {
                update(x, k);
                x = f[x][k];
                update(y, k);
                y = f[y][k];
            }
        }
        update(x,0);
        update(y,0);
    }
    
    int main() {
        scanf("%d%d", &n, &m);
        for (int i=1;i<=n;i++){
            fa[i]=i;
        }
        for (int i = 1; i <= m; i++) {
            scanf("%d%d%d", &a[i].u, &a[i].v, &a[i].w);
        }
        Kruskal();
        dfs(1, 0);
        ans_max = 0x3f3f3f3f3f3f3f3f;
        for (int i = 1; i <= m; i++) {
            if (!a[i].vis) {
                lca(a[i].u, a[i].v);
                if (val1 != a[i].w)
                    ans_max = min(ans_max, ans - val1 + a[i].w);
                else ans_max = min(ans_max, ans - val2 + a[i].w);
            }
        }
        printf("%lld
    ", ans_max);
    }
    

      

  • 相关阅读:
    23.safari history.back的一个坑
    22.一个小小的广播效果
    UI13-GET POST 同步,异步-代理 Block请求方式。
    UI11-数据解析:Json DOM SAX 解析
    UI10-通讯录
    UI-09 cell 高度自适应)
    UI06-scrollView 滚动视图 pagecontroll 页面控制
    UI05-‍手势用图片做实验
    UI04-NSTimer 打地鼠
    UI03-viewController 视图跳转:
  • 原文地址:https://www.cnblogs.com/Accpted/p/11422271.html
Copyright © 2020-2023  润新知