• [BJWC2010] 严格次小生成树


    传送门:>Here<

    给出一张带权无向图,求其严格次小生成树。($n leq 10^5$)

    解题思路

    图的生成树有一个性质:将一条非树边加入后必定形成环。Kruscal求最小生成树其实就是一个贪心地过程:剔除每个环上最大的那一条边。

    那么反过来,求次小生成树就是在某个环上换回最大边,删去原来最大边以保证增量最小的过程。由于题目要求严格,会碰到最大边等于原先最大边的情况,此时就删去原先严格次大边。

    于是现在就是一个数据结构维护的问题了。预处理出最小生成树,维护树链上最大值和次大值,可以树剖或者在倍增LCA的过程中维护。

    如果够无聊,LCT也可以。LCT求最小生成树不用预先对边排序,由于可以动态连边断边,是完全可以根据最小生成树的性质直接维护的——每发现一条边形成了环,如果更优就直接LinkCut更新,保证了全局的最优性。再在Splay上维护边权的最小值就解决了。

    $Code$

    /*By QiXingzhi*/
    #include <cstdio>
    #include <vector>
    #include <algorithm>
    #define  N  (100010)
    #define  M  (300010)
    #define  INF   (21474836470000)
    #define  Max(a,b)  (((a)>(b)) ? (a) : (b))
    #define  Min(a,b)  (((a)<(b)) ? (a) : (b))
    typedef long long ll;
    using namespace std;
    #define int ll
    inline void read(int &x){
        x = 0; int w = 1; register int c = getchar();
        while(c ^ '-' && (c < '0' || c > '9')) c = getchar();
        if(c == '-') w = -1, c = getchar();
        while(c >= '0' && c <= '9') x = (x << 3) +(x << 1) + c - '0', c = getchar(); x *= w;
    }
    struct Edge{
        int x,y,z;
    };
    struct Graph{
        int to,cost;
    };
    Edge a[M];
    bool t_edge[M];
    vector <Graph> G[N];
    vector <Graph> Gt[N];
    int n,m,krus,krus_num,x,y,ans;
    int par[N],f[N][30],gmax[N][30],gsec[N][30],fa[N],wei[N],depth[N];
    inline void AddEdge(int u, int v, int w){
        Graph e;
        e.to = v;
        e.cost = w;
        G[u].push_back(e);
    }
    inline void AddEdge_2(int u, int v, int w){
        Graph e;
        e.to = v;
        e.cost = w;
        Gt[u].push_back(e);
    }
    inline void Swap(int& a, int &b){
        int t = a;
        a = b;
        b = t;
    }
    inline bool kruscal_sort_comp(const Edge& a, const Edge& b){
        return a.z < b.z;
    }
    int krus_find(int x){
        if(par[x] == x) return x;
        par[x] = krus_find(par[x]);
        return par[x];
    }
    void build_tree(int x, int ff){
        int sz = Gt[x].size();
        int to;
        for(int i = 0; i < sz; ++i){
            to = Gt[x][i].to;
            if(to != ff){
                fa[to] = x;
                wei[to] = Gt[x][i].cost;
                build_tree(to, x);
            }
        }
    }
    void lca_dfs(int x, int d){
        depth[x] = d;
        for(int k = 1; (1<<k) < d; ++k){
            f[x][k] = f[f[x][k-1]][k-1];
            gmax[x][k] = Max(gmax[x][k-1], gmax[f[x][k-1]][k-1]);
            if(gmax[x][k-1] == gmax[f[x][k-1]][k-1]){
                gsec[x][k] = Max(gsec[x][k-1], gsec[f[x][k-1]][k-1]);
            }
            else if(gmax[x][k-1] > gmax[f[x][k-1]][k-1]){
                gsec[x][k] = Max(gsec[x][k-1], gmax[f[x][k-1]][k-1]);
            }
            else if(gmax[x][k-1] < gmax[f[x][k-1]][k-1]){
                gsec[x][k] = Max(gmax[x][k-1], gsec[f[x][k-1]][k-1]);
            }
        }
        int sz = Gt[x].size();
        int to;
        for(int i = 0; i < sz; ++i){
            to = Gt[x][i].to;
            if(to != f[x][0]){
                lca_dfs(to, d+1);
            }
        }
    }
    inline void Update(int i){
        int u = a[i].x, v = a[i].y, w = a[i].z, res;
        int val1 = -INF, val2 = -INF;
        if(depth[u] > depth[v]) Swap(u,v);
        for(int k = 20; k >= 0; --k){
            if(depth[u] <= depth[v] - (1<<k)){
                if(gmax[v][k] < val1){
                    val2 = Max(gmax[v][k], val2);
                }
                else if(gmax[v][k] == val1){
                    val2 = Max(val2, gsec[v][k]);
                }
                else if(gmax[v][k] > val1){
                    val2 = Max(gsec[v][k], val1);
                }
                val1 = Max(val1, gmax[v][k]);
                v = f[v][k];
            }
        }
        if(u != v){
            for(int k = 20; k >= 0; --k){
                if(f[u][k] != f[v][k]){
                    if(gmax[u][k] < val1){
                        val2 = Max(val2, gmax[u][k]);
                    }
                    else if(gmax[u][k] == val1){
                        val2 = Max(val2, gsec[u][k]);
                    }
                    else{
                        val2 = Max(val1, gsec[u][k]);
                    }
                    if(gmax[v][k] < val1){
                        val2 = Max(val2, gmax[v][k]);
                    }
                    else if(gmax[v][k] == val1){
                        val2 = Max(val2, gsec[v][k]);
                    }
                    else{
                        val2 = Max(val1, gsec[v][k]);
                    }
                    val1 = Max(val1, gmax[u][k]);
                    val1 = Max(val1, gmax[v][k]);
                    u = f[u][k];
                    v = f[v][k];
                }
            }
            val1 = Max(val1, Max(gmax[u][0], gmax[v][0]));
            if(val2 < gmax[u][0] && gmax[u][0] < val1) val2 = gmax[u][0];
            if(val2 < gmax[v][0] && gmax[v][0] < val1) val2 = gmax[v][0];
        }
        if(val1 < w){
            res = krus - val1 + w;
        }
        else if(val1 == w){
            res = krus - val2 + w;
        }
        ans = Min(ans, res);
    }
    #undef int
    int main(){
        #define int ll
    //    freopen(".in","r",stdin);
        read(n), read(m);
        for(int i = 1; i <= m; ++i){
            read(a[i].x), read(a[i].y), read(a[i].z);
            AddEdge(a[i].x,a[i].y,a[i].z);
            AddEdge(a[i].y,a[i].x,a[i].z);
        }
        sort(a+1, a+m+1, kruscal_sort_comp);
        for(int i = 1; i <= n; ++i) par[i] = i;
        for(int i = 1; i <= m; ++i){
            x = krus_find(a[i].x);
            y = krus_find(a[i].y);
            if(x != y){
                par[x] = y;
                ++krus_num;
                krus += a[i].z;
                t_edge[i] = 1;
                AddEdge_2(a[i].x,a[i].y,a[i].z);
                AddEdge_2(a[i].y,a[i].x,a[i].z);
            }
            if(krus_num >= n-1) break;
        }
        build_tree(1, 0);
        for(int i = 1; i <= n; ++i){
            f[i][0] = fa[i];
            gmax[i][0] = wei[i];
            gsec[i][0] = -INF;
        }
        lca_dfs(1,1);
        ans = INF;
        for(int i = 1; i <= m; ++i){
            if(!t_edge[i]){
                Update(i);
            }
        }
        printf("%lld",ans);
        return 0;
    }
  • 相关阅读:
    git命令log与reflog的比较
    git基础仓库提交到新仓库,保存老仓库历史,并同步老仓库跟新到新仓库中
    classpath*与classpath
    fastjson将对象和json互转,@JSONField的使用及不生效
    feign接口自动生成工具
    IIS .Net Core 413错误和Request body too large解决办法
    thinphp 上传文件到七牛
    php 整合微信、支付宝扫码付款
    Jenkins:整合SonarQube8
    Jenkins:流水线打包运行boot项目
  • 原文地址:https://www.cnblogs.com/qixingzhi/p/9242949.html
Copyright © 2020-2023  润新知