P4180 [BJWC2010]題解

Jefferyzzzz發表於2024-10-05

傳送門:https://www.luogu.com.cn/problem/P4180

類似於CF1108F,而由於嚴格次小,可能出現非樹邊與生成樹上最大邊權相同的情況,我們需要預處理樹上最大和嚴格次大邊。

#include <bits/stdc++.h>

#define int long long
#define inf 0x3f3f3f3f3f3f3f3f

using namespace std;
const int N = 6e5 + 10;

inline int read() {
    char c;
    bool flag = false;
    while ((c = getchar()) < '0' || c > '9') if (c == '-') flag = true;
    int res = c - '0';
    while ((c = getchar()) >= '0' && c <= '9') res = (res << 3) + (res << 1) + c - '0';
    return flag ? -res : res;
}

struct E {
    int u, v, w, used;

    bool operator<(const E &other) const { return w < other.w; }
} e[N];

int pa[N], head[N], cnt, dep[N], fa[N][26], Max[N][26][2];

int get(int u) { return pa[u] == u ? u : pa[u] = get(pa[u]); }

struct Edge {
    int to, next, w;
} edge[N];

void add_edge(int u, int v, int w) {
    edge[cnt].w = w;
    edge[cnt].to = v;
    edge[cnt].next = head[u];
    head[u] = cnt++;
}

void dfs(int x, int f) {
    dep[x] = dep[f] + 1;
    fa[x][0] = f;
    Max[x][0][1] = -inf;
    for (int i = 1; i <= 25; ++i) {
        fa[x][i] = fa[fa[x][i - 1]][i - 1];
        int temp[4] = {Max[x][i - 1][0], Max[fa[x][i - 1]][i - 1][0], Max[x][i - 1][1], Max[fa[x][i - 1]][i - 1][1]};
        sort(temp, temp + 4);
        Max[x][i][0] = temp[3];
        Max[x][i][1] = temp[2] == temp[3] ? temp[1] : temp[2];
    }
    for (int i = head[x]; ~i; i = edge[i].next) {
        int y = edge[i].to, w = edge[i].w;
        if (y == f) continue;
        Max[y][0][0] = w;
        Max[y][0][1] = -inf;
        dfs(y, x);
    }
}

int getAns(int x, int lca, int val) {
    int m0 = -inf, m1 = -inf;
    for (int i = 25; i >= 0; --i) {
        if (dep[fa[x][i]] >= dep[lca]) {
            if (Max[x][i][0] > m0) m1 = max(m0, Max[x][i][1]), m0 = Max[x][i][0];
            else if (Max[x][i][0] > m1 && Max[x][i][0] != m0) m1 = Max[x][i][0];
            else if (Max[x][i][0] > m1 && Max[x][i][0] == m0) m1 = max(Max[x][i][1], m1);
            x = fa[x][i];
        }
    }
    //cout << "m0:" << m0 << " m1:" << m1 << " val:" << val << endl;
    //if (m1 == m0 && m1 != -inf) cout << "SOS";
    return m0 == val ? m1 : m0;
}

int lca(int x, int y) {
    if (dep[x] < dep[y]) swap(x, y);
    for (int i = 25; i >= 0; --i) {
        if (dep[fa[x][i]] >= dep[y]) x = fa[x][i];
    }
    if (x == y) return x;
    for (int i = 25; i >= 0; --i) {
        if (fa[x][i] != fa[y][i]) x = fa[x][i], y = fa[y][i];
    }
    return fa[x][0];
}

signed main() {
    memset(head, -1, sizeof head);
    int n = read(), m = read();
    for (int i = 1; i <= m; ++i) {
        e[i].u = read(), e[i].v = read(), e[i].w = read();
        pa[i] = i;
    }
    sort(e + 1, e + m + 1);
    int ans = inf, res = 0;
    for (int i = 1; i <= m; ++i) {
        int u = e[i].u, v = e[i].v;
        if (get(u) != get(v)) {
            pa[get(u)] = get(v);
            add_edge(u, v, e[i].w);
            add_edge(v, u, e[i].w);
            res += e[i].w;
            e[i].used = 1;
        }
    }
    dfs(1, 0);
    for (int i = 1; i <= m; ++i) {
        if (!e[i].used && e[i].u != e[i].v) {
            //cout << e[i].w << endl;
            int LCA = lca(e[i].u, e[i].v);
            int tmp = max(getAns(e[i].u, LCA, e[i].w), getAns(e[i].v, LCA, e[i].w));
            if (tmp <= -inf) continue;
            ans = min(ans, res + e[i].w - tmp);
            //cout << "tmp:" << tmp << " Res:" << res + e[i].w - tmp << endl;
        }
    }
    printf("%lld\n", ans);
    return 0;
}