P4180 [BJWC2010]严格次小生成树

P4180 BJWC2010严格次小生成树

先求一遍最小生成树。然后枚举加入哪条边,然后找这两个端点的LCA,记录路径上的最大值和严格次大值(我用了一种偷懒的方法,不过能过)。为什么记录严格次大值?因为我们需要注意最大值等于你加入的边的情况。

/*
Name: P4180
Copyright: NO
Author: Gensokyo_Alice
Date: 25/9/20 17:46
Description:
*/
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <queue>
#include <stack>
#include <cmath>
#include <set>
#include <map>

using namespace std;

typedef long long ll;
const ll MAXN = 1e6+10;
const ll INF = 0x3f3f3f3f3f3f3f3f;

struct edge {
    ll nt, to, v;
} E[MAXN];

struct edg {
    ll x, y, v;
    friend bool operator < (edg a, edg b) {
        return a.v < b.v;
    }
} e[MAXN];

struct zt {
    ll m1, m2, n;
};

ll q[4], tq, N, M, vis[MAXN], fa[MAXN], W, head[MAXN], cnt = -1, siz[MAXN], dep[MAXN], f[MAXN][22], dis[MAXN][2][22];

zt lca(ll, ll);
void add(ll, ll, ll);
void dfs(ll, ll);
ll find_(ll);
void krus();
void onion(ll, ll);

int main() {
    memset(head, -1, sizeof(head));
	ios::sync_with_stdio(false);
	#ifdef ZZCAKIOI
	#endif
    cin >> N >> M;
    for (ll i = 1; i <= M; i++) cin >> e[i].x >> e[i].y >> e[i].v;
    for (ll i = 1; i <= N; i++) fa[i] = i, siz[i] = 1;
    krus();
    dfs(1, 0);
    ll ans = INF;
    for (ll i = 1; i <= M; i++) {
        if (vis[i]) continue;
        zt now = lca(e[i].x, e[i].y);
        if (e[i].v == now.m1) ans = min(W - now.m2 + e[i].v, ans);
        else ans = min(W - now.m1 + e[i].v, ans);
    }
    cout << ans << '\n';
	return 0;
}

zt lca(ll x, ll y) {
    zt ret = {0, 0, 0};
    if (dep[x] < dep[y]) swap(x, y);
    ll di = dep[x] - dep[y];
    for (ll i = 20; ~i; i--) {
        if ((di >> i) & 1) {
            q[0] = dis[x][0][i], q[1] = dis[x][1][i];
            q[2] = ret.m1, q[3] = ret.m2;
		    sort(q, q+4);
		    tq = unique(q, q+4) - q;
            ret.m1 = q[tq-1], ret.m2 = q[tq-2];
            x = f[x][i];
        }
    }
    if (x == y) return ret;
    for (ll i = 20; ~i; i--) {
        if (f[x][i] != f[y][i]){
            q[0] = dis[x][0][i], q[1] = dis[x][1][i];
            q[2] = ret.m1, q[3] = ret.m2;
		    sort(q, q+4);
		    tq = unique(q, q+4) - q;
		    ret.m1 = q[tq-1], ret.m2 = q[tq-2];
            q[0] = ret.m1, q[1] = ret.m2;
            q[2] = dis[y][0][i], q[3] = dis[y][1][i];
		    sort(q, q+4);
		    tq = unique(q, q+4) - q;
            ret.m1 = q[tq-1], ret.m2 = q[tq-2];
            x = f[x][i], y = f[y][i];
        }
    }
    q[0] = dis[x][0][0], q[1] = dis[x][1][0];
    q[2] = ret.m1, q[3] = ret.m2;
    sort(q, q+4);
    tq = unique(q, q+4) - q;
    ret.m1 = q[tq-1], ret.m2 = q[tq-2];
    q[2] = dis[y][0][0], q[3] = dis[y][1][0];
    q[1] = ret.m1, q[0] = ret.m2;
    sort(q, q+4);
    tq = unique(q, q+4) - q;
    ret.m1 = q[tq-1], ret.m2 = q[tq-2];
    return ret;
}

void dfs(ll n, ll ff) {
    dep[n] = dep[ff] + 1;
    f[n][0] = ff;
    for (ll i = 1; i <= 20; i++) {
        f[n][i] = f[f[n][i-1]][i-1];
        q[0] = dis[n][0][i-1], q[1] = dis[n][1][i-1];
        q[2] = dis[f[n][i-1]][0][i-1], q[3] = dis[f[n][i-1]][1][i-1];
        sort(q, q+4);
        tq = unique(q, q+4) - q;
        dis[n][0][i] = q[tq-1], dis[n][1][i] = q[tq-2];
    }
    for (ll i = head[n]; ~i; i = E[i].nt) {
        ll v = E[i].to;
        if (v == ff) continue;
        else {
            dis[v][0][0] = E[i].v;
            dfs(v, n);
        }
    }
}

void krus() {
    sort(e+1, e+M+1);
    for (ll i = 1, ct = 0; i <= M && ct < N-1; i++) {
        ll fx = find_(e[i].x), fy = find_(e[i].y);
        if (fx != fy) {
            onion(fx, fy), ct++, W += e[i].v;
            add(e[i].x, e[i].y, e[i].v);
            add(e[i].y, e[i].x, e[i].v);
            vis[i] = 1;
        }
    }
}

void onion(ll x, ll y) {
    ll fx = find_(x), fy = find_(y);
    if (siz[fx] < siz[fy]) fa[fx] = fy, siz[fx] += siz[fy];
    else fa[fy] = fx, siz[fy] += siz[fx];
}

void add(ll x, ll y, ll v) {E[++cnt] = {head[x], y, v}, head[x] = cnt;}
ll find_(ll x) {return fa[x] == x ? x : fa[x] = find_(fa[x]);}
上一篇:牛客高频题--树的层次遍历


下一篇:Helper2416开发板学习③搭建/lib链接库