管理员聚聚别封我,不是滥用评测器,只是想知道是因为什么RE,QaQ
初步判定是kruskal的“if (Fa != Fb) { p[Fa] = Fb;……}”部分有问题,求改
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10, M = 6e5 + 10;
const int INF = 0x3f3f3f3f;
int p[N], n, m;
struct E {
int a, b, w;
bool operator< (const E &W) const {
return w < W.w;
}
} edge[M];
int find(int x) {
if (p[x] != x) p[x] = find(p[x]);
else return x;
}
int use[M]; //是否在最小生成树内
int res = 0;
int h[N], e[M], w[M], ne[M], idx;
void add(int a, int b, int c) // 添加一条边a->b,边权为c
{
e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx ++ ;
}
void kruskal() {
int cnt = 0;
for (int i = 1; i <= m; i++) {
int a = edge[i].a, b = edge[i].b, w = edge[i].w;
int Fa = find(a), Fb = find(b);
if (Fa != Fb) {
p[Fa] = Fb;
use[i] = true; //在最小生成树内
add(a, b, w); add(b, a, w); //建树
cnt++; res += w;
}
if (cnt == n - 1) return;
}
}
int fa[N][30], fi[N][30], se[N][30]; //2^i级祖先,倍增路径最大次大值
int dep[N];
void dfs(int u, int father) {
dep[u] = dep[father] + 1; fa[u][0] = father;
for (int i = h[u]; ~i; i = ne[i]) {
int v = e[i];
if (v == father) continue;
fi[v][0] = w[i];
dfs(v, u);
}
}
int lca(int x, int y) {
if (dep[x] < dep[y]) swap(x, y);
for (int i = 15; i >= 0; i--)
if (dep[fa[x][i]] >= dep[y]) x = fa[x][i];
if (x == y) return x;
for (int i = 15; i >= 0; i--)
if (fa[x][i] != fa[y][i]) x = fa[x][i], y = fa[y][i];
return fa[x][0];
}
void init() {
for (int i = 1; i <= 15; i++) {
for (int j = 1; j <= n; j++) {
fa[j][i] = fa[fa[j][i - 1]][i - 1];
fi[j][i] = max(fi[j][i - 1], fi[fa[j][i - 1]][i - 1]);
se[j][i] = max(se[j][i - 1], se[fa[j][i - 1]][i - 1]);
if (fi[j][i - 1] < fi[fa[j][i - 1]][i - 1]) se[j][i] = max(se[j][i], fi[j][i - 1]);
else if (fi[j][i - 1] > fi[fa[j][i - 1]][i - 1]) se[j][i] = max(se[j][i], fi[fa[j][i - 1]][i - 1]);
}
}
}
int Max(int u, int grandpa, int q) {
int ans = 0;
for (int i = 15; i >= 0; i--) {
if (dep[fa[u][i]] >= dep[grandpa]) { //拆分成log个小段计算
if (fi[u][i] == q) ans = max(ans, se[u][i]);
else ans = max(ans, fi[u][i]);
u = fa[u][i];
}
}
return ans;
}
int ans = 0;
int main() {
memset(h, -1, sizeof h);
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++) p[i] = i;
for (int i = 1; i <= m; i++) {
int a, b, c; scanf("%d%d%d", &a, &b, &c);
edge[i] = {a, b, c};
}
sort(edge + 1, edge + 1 + m);
kruskal();
dfs(1, 0);
init();
ans = INF;
for (int i = 1; i <= m; i++) {
if (use[i]) continue; //选择非树边进行计算
int u = edge[i].a, v = edge[i].b, z = edge[i].w;
int LCA = lca(u, v);
int m1 = Max(u, LCA, z), m2 = Max(v, LCA, z);
//cout << i << ' ' << m1 << ' ' << m2 << endl;
if (max(m1, m2) != z) ans = min(ans, res + z - max(m1, m2));
}
printf("%d\n", ans);
//for (int i = 0; i <= 5; i++, puts(""))
// for (int j = 1; j <= n; j++) cout << se[j][i] << ' ';
return 0;
}