传送门
如题,严格次小生成树
分析
对于
K
r
u
s
k
a
l
Kruskal
Kruskal 执行过程中
先构造最小生成树,然后再贪心的删边
剩下没有参与构造生成树的边,对于边的两个端点
用这条边(记为
A
A
A边),替换生成树两个端点路径上面的一条边(记为
B
B
B边)
严格次小,
A
A
A 边一定严格 大于
B
B
B 的
我们要求的是对于每条能够替换的边,
v
(
A
)
−
v
(
B
)
v(A)-v(B)
v(A)−v(B)最小即可
倍增维护生成树链上边的最大值和次大值,按照上面的规则尝试替换边
代码
//P4180
/*
@Author: YooQ
*/
#include <bits/stdc++.h>
using namespace std;
#define sc scanf
#define pr printf
#define ll long long
#define int long long
#define FILE_OUT freopen("out", "w", stdout);
#define FILE_IN freopen("in", "r", stdin);
#define debug(x) cout << #x << ": " << x << "\n";
#define AC 0
#define WA 1
#define INF 0x3f3f3f3f
const ll MAX_N = 1e6+5;
const ll MOD = 1e9+7;
int N, M, K;
int head[MAX_N];
int tot = 0;
struct Edge {
int to, nxt, w;
}edge[MAX_N];
void addEdge(int u, int v, int w) {
edge[tot].nxt = head[u];
edge[tot].to = v;
edge[tot].w = w;
head[u] = tot++;
edge[tot].nxt = head[v];
edge[tot].to = u;
edge[tot].w = w;
head[v] = tot++;
}
bool use[MAX_N];
struct Node {
int x, y, w;
}node[MAX_N];
int father[MAX_N];
int find(int x) {
return x == father[x] ? x : father[x] = find(father[x]);
}
int dep[MAX_N];
int parent[MAX_N][22];
int maxx[MAX_N][22];
int maxx2[MAX_N][22];
void dfs(int u, int from) {
dep[u] = dep[from] + 1;
parent[u][0] = from;
for (int i = 1; i <= 20; ++i) {
parent[u][i] = parent[parent[u][i-1]][i-1];
maxx[u][i] = max(maxx[parent[u][i-1]][i-1], maxx[u][i-1]);
maxx2[u][i] = max(maxx2[parent[u][i-1]][i-1], maxx2[u][i-1]);
if (maxx[parent[u][i-1]][i-1] != maxx[u][i-1]) {
maxx2[u][i] = max(maxx2[u][i], min(maxx[parent[u][i-1]][i-1], maxx[u][i-1]));
}
}
int v;
for (int i = head[u];~i;i=edge[i].nxt) {
if ((v=edge[i].to) == from) continue;
maxx[v][0] = edge[i].w;
maxx2[v][0] = 0;
dfs(v, u);
}
}
int LCA(int x, int y) {
if (dep[x] < dep[y]) swap(x, y);
for (int i = 20; i+1; --i) {
if (dep[parent[x][i]] >= dep[y]) {
x = parent[x][i];
}
}
if (x == y) return x;
for (int i = 20; i+1; --i) {
if (parent[x][i] != parent[y][i]) {
x = parent[x][i];
y = parent[y][i];
}
}
return parent[x][0];
}
int get_max(int u, int lca, int limit) {
int res = 0;
for (int i = 20; i+1; --i) {
if (dep[parent[u][i]] >= dep[lca]) {
if (maxx[u][i] < limit) {
res = max(res, maxx[u][i]);
}
if (maxx2[u][i] < limit) {
res = max(res, maxx2[u][i]);
}
u = parent[u][i];
}
}
return res;
}
void init() {
memset(head, -1, sizeof head);
tot = 0;
}
void solve(){
init();
cin >> N >> M;
int u, v, w;
for (int i = 1; i <= M; ++i) {
cin >> u >> v >> w;
node[i] = {u, v, w};
}
sort(node+1, node+1+M, [](Node a, Node b){return a.w < b.w;});
for (int i = 1; i <= N; ++i) {
father[i] = i;
}
int done = 1;
int x, y;
int ans = 0;
for (int i = 1; i <= M && done < N; ++i) {
x = find(node[i].x);
y = find(node[i].y);
if (x == y) continue;
use[i] = 1;
ans += node[i].w;
++done;
father[x] = y;
addEdge(node[i].x, node[i].y, node[i].w);
}
dfs(1, 0);
int res = 1e18;
for (int i = 1; i <= M; ++i) {
if (use[i]) continue;
x = node[i].x;
y = node[i].y;
int lca = LCA(x, y);
int a = get_max(x, lca, node[i].w);
int b = get_max(y, lca, node[i].w);
res = min(res, ans - max(a, b) + node[i].w);
}
cout << res;
}
signed main()
{
#ifndef ONLINE_JUDGE
//FILE_IN
FILE_OUT
#endif
int T = 1;//cin >> T;
while (T--) solve();
return AC;
}