zoukankan      html  css  js  c++  java
  • [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;
    }
  • 相关阅读:
    LeetCode OJ String to Integer (atoi) 字符串转数字
    HDU 1005 Number Sequence(AC代码)
    HDU 1004 Let the Balloon Rise(AC代码)
    HDU 1003 Max Sum(AC代码)
    012 Integer to Roman 整数转换成罗马数字
    011 Container With Most Water 盛最多水的容器
    010 Regular Expression Matching 正则表达式匹配
    007 Reverse Integer 旋转整数
    006 ZigZag Conversion
    005 Longest Palindromic Substring 最长回文子串
  • 原文地址:https://www.cnblogs.com/qixingzhi/p/9242949.html
Copyright © 2011-2022 走看看