zoukankan      html  css  js  c++  java
  • 【洛谷】4180:【模板】严格次小生成树[BJWC2010]【链剖】【线段树维护最大、严格次大值】

    P4180 【模板】严格次小生成树[BJWC2010]

    题目描述

    小C最近学了很多最小生成树的算法,Prim算法、Kurskal算法、消圈算法等等。正当小C洋洋得意之时,小P又来泼小C冷水了。小P说,让小C求出一个无向图的次小生成树,而且这个次小生成树还得是严格次小的,也就是说:如果最小生成树选择的边集是EM,严格次小生成树选择的边集是ES,那么需要满足:(value(e)表示边e的权值)$sum_{e in E_M}value(e)<sum_{e in E_S}value(e)$

    这下小 C 蒙了,他找到了你,希望你帮他解决这个问题。

    输入输出格式

    输入格式:

     

    第一行包含两个整数N 和M,表示无向图的点数与边数。 接下来 M行,每行 3个数x y z 表示,点 x 和点y之间有一条边,边的权值为z。

     

    输出格式:

     

    包含一行,仅一个数,表示严格次小生成树的边权和。(数据保证必定存在严格次小生成树)

    输入输出样例

    输入样例#1: 复制
    5 6
    1 2 1 
    1 3 2 
    2 4 3 
    3 5 4 
    3 4 3 
    4 5 6 
    输出样例#1: 复制
    11

    说明

    数据中无向图无自环; 50% 的数据N≤2 000 M≤3 000; 80% 的数据N≤50 000 M≤100 000; 100% 的数据N≤100 000 M≤300 000 ,边权值非负且不超过 10^9 。


    Solution

    无所不能的链剖Orz!(就是太难调叻!!)

    对于一条不在最小生成树上的边,如果要使它在次小生成树上,那就是在这条边的两端点的链的所有边中找一条删掉,要使他最接近次小,那么就是找链中最大的边,这样使增加的边权最小。但是题目要求是严格次小,意味着如果最大边权等于这条非树边边权,那么我们要找次大的边权。

    因此线段树上再维护一个严格次大值就好了。

    线段树的值是点权下放到边权。所以跳链查询时最后要查询的是$in[v]+1$到$in[u]$,防止把上面的边计算进去。

    Code

    #include<bits/stdc++.h>
    #define LL long long
    using namespace std;
    
    struct Node {
        int u, v, nex, tag; LL w;
        Node(int u = 0, int v = 0, int nex = 0, LL w = 0) :
            u(u), v(v), nex(nex), w(w) { }
    } Edge[600005], a[300005];
    bool cmp(Node a, Node b) { return a.w < b.w; }
    
    int h[100005], stot;
    void add(int u, int v, LL w) {
        Edge[++stot] = Node(u, v, h[u], w);
        h[u] = stot;
    }
    
    int n, m;
    int fa[100005], siz[100005], son[100005], dep[100005]; LL vson[100005];
    void dfs1(int u, int f) {
        fa[u] = f;    siz[u] = 1;    dep[u] = dep[f] + 1;
        for(int i = h[u]; i; i = Edge[i].nex) {
            int v = Edge[i].v;
            if(v == f)    continue;
            dfs1(v, u);
            siz[u] += siz[v];
            if(siz[v] > siz[son[u]])    son[u] = v, vson[u] = Edge[i].w;
        }
    }
    
    int top[100005], in[100005], idc; LL seq[100005];
    void dfs2(int u, int t, LL w) {
        top[u] = t;    in[u] = ++idc; seq[idc] = w;
        if(son[u])    dfs2(son[u], t, vson[u]);
        for(int i = h[u]; i; i = Edge[i].nex) {
            int v = Edge[i].v;
            if(v == fa[u] || v == son[u])    continue;
            dfs2(v, v, Edge[i].w);
        }
    }
    
    struct QAQ {
        LL ma1, ma2;
    } TR[400005];
    
    void update(int nd) {
        TR[nd].ma1 = max(TR[nd << 1].ma1, TR[nd << 1 | 1].ma1);
        TR[nd].ma2 = max(TR[nd].ma1 == TR[nd << 1].ma1 ? TR[nd << 1].ma2 : TR[nd << 1].ma1, TR[nd].ma1 == TR[nd << 1 | 1].ma1 ? TR[nd << 1 | 1].ma2 : TR[nd << 1 | 1].ma1);
    }
    
    void build(int nd, int l, int r) {
        if(l == r) {
            TR[nd].ma1 = seq[l];
            TR[nd].ma2 = -1;
            return ;
        }
        int mid = (l + r) >> 1;
        build(nd << 1, l, mid);
        build(nd << 1 | 1, mid + 1, r);
        update(nd);
    }
    
    QAQ query(int nd, int l, int r, int L, int R) {
        if(l >= L && r <= R)    return TR[nd];
        int mid = (l + r) >> 1;
        QAQ ans, tmp, res;
        ans.ma1 = ans.ma2 = tmp.ma1 = tmp.ma2 = res.ma1 = res.ma2 = 0;
        if(L <= mid) {
            ans = query(nd << 1, l, mid, L, R);
        }
        if(R > mid)     {
            tmp = query(nd << 1 | 1, mid + 1, r, L, R);
        }
        res.ma1 = max(ans.ma1, tmp.ma1);
        res.ma2 = max(ans.ma1 == res.ma1 ? ans.ma2 : ans.ma1, tmp.ma1 == res.ma1 ? tmp.ma2 : tmp.ma1);
        return res;
    }
    
    LL query(int u, int v, LL w) {
        LL ans = 0;
        while(top[u] != top[v]) {
            if(dep[top[u]] < dep[top[v]])    swap(u, v);
            QAQ tmp = query(1, 1, n, in[top[u]], in[u]);
            ans = max(tmp.ma1 == w ? tmp.ma2 : tmp.ma1, ans);
            u = fa[top[u]];
        }
        if(u == v)    return ans;
        if(dep[u] < dep[v])    swap(u, v);
        QAQ tmp = query(1, 1, n, in[v] + 1, in[u]);
        ans = max(ans, tmp.ma1 == w ? tmp.ma2 : tmp.ma1);
        return ans;
    }
    
    int f[100005];
    int find(int x) {
        if(x != f[x])    return f[x] = find(f[x]);
        return f[x];
    }
    
    LL tot;
    void Kruskal() {
        sort(a + 1, a + 1 + m, cmp);
        for(int i = 1; i <= n; i ++)    f[i] = i;
        for(int i = 1; i <= m; i ++) {
            int u = a[i].u, v = a[i].v; LL w = a[i].w;
            int uu = find(u), vv = find(v);
            if(uu != vv)    f[uu] = vv, a[i].tag = 1, tot += w;
        }
    }
    
    int main() {
        scanf("%d%d", &n, &m);
        for(int i = 1; i <= m; i ++) {
            int u, v; LL w;
            scanf("%d%d%lld", &u, &v, &w);
            a[i].u = u, a[i].v = v, a[i].w = w;
        }
        Kruskal();
        for(int i = 1; i <= m; i ++) 
            if(a[i].tag) {
                add(a[i].u, a[i].v, a[i].w);
                add(a[i].v, a[i].u, a[i].w);
            }
        dfs1(1, 0); dfs2(1, 0, 0); build(1, 1, n);
        LL ans = 0x3f3f3f3f;
        for(int i = 1; i <= m; i ++) {
            if(!a[i].tag) {
                int u = a[i].u, v = a[i].v; LL w = a[i].w;
                LL tmp = query(u, v, w);
                ans = min(ans, w - tmp);
            }
        }
        printf("%lld", tot + ans);
        return 0;
    }
  • 相关阅读:
    linux系统命令学习系列-用户切换命令su,sudo
    linux系统命令学习系列-用户组管理
    linux系统命令学习-用户管理
    python web开发-flask中sqlalchemy的使用
    python web开发-flask连接sqlite数据库
    python实现bt种子 torrent转magnet
    prefProvider.kt
    douyin-bot-代码
    pyadb关于python操作adb的资料
    bottle源码
  • 原文地址:https://www.cnblogs.com/wans-caesar-02111007/p/9812827.html
Copyright © 2011-2022 走看看