1. 程式人生 > >【洛谷】4180:【模板】嚴格次小生成樹[BJWC2010]【鏈剖】【線段樹維護最大、嚴格次大值】

【洛谷】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;
}