题意:好长啊 求一棵生成树,首先满足最短边最大,其次使任意两点路径上的最短边之和最小。
思路:要使最短边取最大值,考虑二分最短边,判断当前能否生成一棵树,如果可以,考虑使任意两点路径上的最短边之和最小,也就是说,其余的边应该尽量小,即求最小生成树。建完图之后跑一遍任意两点路径上的最短边和就可以了。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const double eps = 1e-8;
const double PI = acos(-1.0);
const int inf = 0x3f3f3f3f;
const int mod = 1e9 + 27;
const int N = 2e4 + 7;
const int M = 1e6 + 7;
int n, m;
int head[N], tot, nxt[N], to[N], val[N], fa[N], siz[N];
int mi, id, X, Y;
bool vis[N];
struct Edge {
int u, v, w;
bool operator < (const Edge &a) const {
return w < a.w;
}
} edge[M];
void addedge(int u, int v, int w) {
to[++tot] = v;
nxt[tot] = head[u];
val[tot] = w;
head[u] = tot;
}
int Find(int x) {
if(x == fa[x]) return x;
return fa[x] = Find(fa[x]);
}
bool Union(int x, int y) {
int xx = Find(x);
int yy = Find(y);
if(xx != yy) {
fa[xx] = yy;
return 1;
}
return 0;
}
void get(int x, int fa) {
siz[x] = 1;
for(int i = head[x]; i; i = nxt[i]) {
int v = to[i], w = val[i];
if(vis[i] || v == fa) continue;
get(v, x);
siz[x] += siz[v];
if(w < mi) {
mi = w;
id = i;
Y = v, X = x;
}
}
}
ll dfs(int x) {
bool flag = 0;
for(int i = head[x]; i; i = nxt[i]) {
if(vis[i]) continue;
flag = 1;
break;
}
if(!flag) return 0;
mi = 1e9, id = 0;
get(x, -1);
vis[id] = 1, vis[id ^ 1] = 1;
ll num = 1ll * (siz[x] - siz[Y]) * siz[Y] * mi;
int _x = X, _y = Y;
return num + dfs(_x) + dfs(_y);
}
bool check(int pos, bool flag) {
for(int i = 1; i <= n; ++i) fa[i] = i;
int cnt = 0;
for(int i = pos; i <= m; ++i) {
int xx = Find(edge[i].u);
int yy = Find(edge[i].v);
int w = edge[i].w;
if(Union(xx, yy)) {
///只对最后一次建图
if(flag) {
addedge(edge[i].u, edge[i].v, w);
addedge(edge[i].v, edge[i].u, w);
}
cnt++;
}
if(cnt >= n - 1) return 1;
}
return 0;
}
int lower_bound(int l, int r) {
while (l < r) {
int mid = (l + r + 1) >> 1;
if (check(mid, 0)) l = mid;
else r = mid - 1;
}
return l;
}
int main() {
tot = 1;
scanf("%d%d", &n, &m);
for(int i = 1; i <= m; ++i)
scanf("%d%d%d", &edge[i].u, &edge[i].v, &edge[i].w);
sort(edge + 1, edge + m + 1);
int minn = lower_bound(1, m);
check(minn, 1);
printf("%lld\n", dfs(1));
return 0;
}