题目大意
就是求严格次小生成树, 即找到一个生成树, 使其子树和大于最小生成树,且最小
solution
那我们怎么求呢?
我们先建出最小生成树肯定不亏,然后我们根据最小生成树的性质,每加入一条边会发现构成了一个环,然后呢我们在这个环中找到最大值和次大值,然后如果最大值和个加入的边不相等就删去最大值,加入这条边,反之删去最小值,加入这条边,然后最大值和最小值可以用倍增来维护
Code:
/**
* Author: Alieme
* Data: 2020.8.31
* Problem: P4180
* Time: O()
*/
#include <cstdio>
#include <iostream>
#include <string>
#include <cstring>
#include <cmath>
#include <algorithm>
#define int long long
#define rr register
#define inf 1e15
#define MAXN 300010
using namespace std;
inline int read() {
int s = 0, f = 0;
char ch = getchar();
while (!isdigit(ch)) f |= ch == '-', ch = getchar();
while (isdigit(ch)) s = s * 10 + (ch ^ 48), ch = getchar();
return f ? -s : s;
}
void print(int x) {
if (x < 0) putchar('-'), x = -x;
if (x > 9) print(x / 10);
putchar(x % 10 + 48);
}
struct Ufs {
int fa[MAXN];
inline void clear(int x) {for (rr int i = 1; i <= x; i++) fa[i] = i;}
int find(int x) {return x == fa[x] ? x : fa[x] = find(fa[x]);}
inline void merge(int x, int y) {x = find(x), y = find(y); if (x != y) fa[x] = y;}
inline bool check(int x, int y) {return find(x) == find(y);}
}S;
struct Gragh {
int u, v, w;
Gragh() {}
Gragh(int U, int V, int W) {u = U, v = V, w = W;}
bool operator <(const Gragh &b) const {return w < b.w;}
}g[MAXN];
struct Edge {
int nxt;
int to;
int val;
Edge() {}
Edge(int Nxt, int To, int Val) {nxt = Nxt, to = To, val = Val;}
}e[MAXN << 1];
int n, m, tot, ans = inf, cnt;
int head[MAXN << 1], dep[MAXN];
int fa[MAXN][30], minn[MAXN][30], maxx[MAXN][30];
bool vis[MAXN];
inline void add(int from, int to, int val) {
e[++tot] = Edge(head[from], to, val);
head[from] = tot;
}
void dfs(int x, int fath) {
fa[x][0] = fath;
dep[x] = dep[fath] + 1;
for (rr int i = head[x]; i; i = e[i].nxt) {
int to = e[i].to;
if (to == fath) continue;
maxx[to][0] = e[i].val;
minn[to][0] = -inf;
dfs(to, x);
}
}
inline void init() {
minn[1][0] = inf;
dfs(1, 0);
for (rr int i = 1; i <= 18; i++)
for (rr int j = 1; j <= n; j++) {
fa[j][i] = fa[fa[j][i - 1]][i - 1];
maxx[j][i] = max(maxx[j][i - 1], maxx[fa[j][i - 1]][i - 1]);
minn[j][i] = min(minn[j][i - 1], minn[fa[j][i - 1]][i - 1]);
if (maxx[j][i - 1] > maxx[fa[j][i - 1]][i - 1]) minn[j][i] = max(minn[j][i], maxx[fa[j][i - 1]][i - 1]);
else if (maxx[j][i - 1] < maxx[fa[j][i - 1]][i - 1]) minn[j][i] = max(minn[j][i], maxx[j][i - 1]);
}
}
inline void kruskal() {
S.clear(n);
sort(g + 1, g + 1 + m);
for (rr int i = 1; i <= m; i++) {
int u = g[i].u, v = g[i].v, w = g[i].w;
if (S.check(u, v)) continue;
vis[i] = 1;
cnt += w;
S.merge(u, v);
add(u, v, w);
add(v, u, w);
}
}
inline int LCA(int x, int y) {
if (dep[x] < dep[y]) swap(x, y);
for (rr int i = 18; i >= 0; i--)
if (dep[fa[x][i]] >= dep[y])
x = fa[x][i];
if (x == y) return x;
for (rr int i = 18; i >= 0; i--)
if (fa[x][i]^fa[y][i])
x = fa[x][i], y = fa[y][i];
return fa[x][0];
}
inline int query(int u, int v, int maxxx) {
int ans = -inf;
for (int i = 18; i >= 0; i--)
if (dep[fa[u][i]] >= dep[v]) {
if (maxxx != maxx[u][i]) ans = max(ans, maxx[u][i]);
else ans = max(ans, minn[u][i]);
// cout << ans << " " << maxx[u][i] << " " << minn[u][i] << "
";
u = fa[u][i];
}
return ans;
}
signed main() {
n = read();
m = read();
for (rr int i = 1; i <= m; i++) g[i].u = read(), g[i].v = read(), g[i].w = read();
kruskal();
init();
for (rr int i = 1; i <= m; i++)
if (!vis[i]) {
int u = g[i].u, v = g[i].v, w = g[i].w;
int lca = LCA(u, v);
int maxu = query(u, lca, w);
int maxv = query(v, lca, w);
ans = min(ans, cnt - max(maxu, maxv) + w);
}
print(ans);
}