原题链接
- 题解:求非严格次小生成树,先钦定一个最小生成树,枚举每一条非树边。可发现加入枚举的这条边,定能成环,然后再在环上断开最大的是树边的一条边,然后枚举取最小值。为了缩小时间瓶颈,用了倍增法,预处理最小生成树上两个点之间到最近公共祖先的路上最长的边长,然后 (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;
}