ACM Contest and Blackout UVA - 10600

原题链接

  • 题解:求非严格次小生成树,先钦定一个最小生成树,枚举每一条非树边。可发现加入枚举的这条边,定能成环,然后再在环上断开最大的是树边的一条边,然后枚举取最小值。为了缩小时间瓶颈,用了倍增法,预处理最小生成树上两个点之间到最近公共祖先的路上最长的边长,然后 \(\log\) 复杂度的查询。
  • 代码:
#include <cstring>
#include <iostream>
#include <queue>
#include <algorithm>
#include <vector>

using namespace std;
const int N = 1111;
const int M = 2 * N * N;
int n, m;
struct edge {
    int u, v, w;
    bool choose;
}e[M];
bool cmp(edge a, edge b) {return a.w < b.w;}
int h[M], ne[M], to[M], W[M], idx;
int ans;
void add(int u, int v, int w) {
    ne[idx] = h[u];
    to[idx] = v;
    W[idx] = w;
    h[u] = idx++;
}
int f[N];
int Find(int x) {return f[x] == x?x:f[x]= Find(f[x]);}
void un(int i) {
    int x = e[i].u;
    int y = e[i].v;
    int fx = Find(x);
    int fy = Find(y);
    if (fx == fy) {
        return;
    }ans += e[i].w;
    add(x, y, e[i].w);
    add(y, x, e[i].w);
    f[fx]  = fy;
    e[i].choose = 1;
}
int dep[N];
int fa[N][20];
int ga[N][20];
void dfs(int u, int father) {
    if (father == -1)dep[u] = 1;
    else dep[u] = dep[father] + 1;
    for (int i = 1; i < 15; i ++) {
        fa[u][i] = fa[fa[u][i-1]][i-1];
        ga[u][i] = max(ga[u][i-1], ga[fa[u][i-1]][i-1]);
    }
    for (int i = h[u]; ~i ;i = ne[i]) {
        int v = to[i];
        if (v != father) {
            fa[v][0] = u;
            ga[v][0] = W[i];
            dfs(v, u);
        }
    }
}
int lca(int u, int v) {
    if (dep[u] < dep[v])swap(u, v);
    int Max = -1;
    for (int i = 14; i >= 0; i--) {
        if (dep[fa[u][i]]>=dep[v]) {
            Max = max(Max, ga[u][i]);
            u = fa[u][i];
        }
    }
    if (u == v)return Max;
    for (int i = 14; i >= 0; i--) {
        if (fa[u][i] != fa[v][i]) {
            Max = max(Max, ga[u][i]);
            Max = max(Max, ga[v][i]);
            u = fa[u][i];
            v = fa[v][i];
        }
    }
    Max = max(Max, ga[u][0]);
    Max = max(Max, ga[v][0]);
    return Max;
}
void solve() {
    int n, m;
    cin >> n >> m;
    for (int i  =1; i <= n; i ++)f[i] = i;
    memset(h, -1, sizeof h);
    memset(dep, 0, sizeof dep);
    ans = idx = 0;
    for (int i = 1;i <= m;i ++) {
        int u, v, w;cin >> u >> v >> w;
        e[i] = {u, v, w};
        e[i].choose = 0;
    }
    sort(e + 1, e + 1 +  m, cmp);
    for (int i = 1; i <= m; i  ++) {
        un(i);
    }
    dfs(1, -1);
    int ans2  = 99999999;
    for (int i = 1; i <= m; i ++) {
        if (!e[i].choose) {
            ans2 = min(ans2, ans + e[i].w - lca(e[i].u, e[i].v));
        }
    }
    cout << ans <<" " << ans2 << endl;
}
signed main() {
    int t;cin >> t;
    while (t--) {
        solve();
    }
    return 0;
}
posted @ 2021-04-09 08:40  u_yan  阅读(37)  评论(0编辑  收藏  举报