专栏文章
题解:P14080 [GESP202509 八级] 最小生成树
P14080题解参与者 2已保存评论 2
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 2 条
- 当前快照
- 1 份
- 快照标识符
- @minqgp9j
- 此快照首次捕获于
- 2025/12/02 06:41 3 个月前
- 此快照最后确认于
- 2025/12/02 06:41 3 个月前
真的有人能在考场上默写出这题吗?
考虑对于边的位置分类讨论,对于非树边,答案即为原图最小生成树的边权和。
对于树边,会将最小生成树分为两个连通块,答案即为所有连接两个连通块的边的最小值。
考虑这个如何维护,不妨把题目转化一下。注意到断掉的边刚好在连接边的路径上。于是我们可以枚举所有非树边,然后更新路径上的最小值。
这个可以用倍增表维护。
最后增加的答案即为连上的边减去断掉的边,注意特判 。
CPP#include <bits/stdc++.h>
#define int long long
using namespace std;
using i32 = int32_t;
using i64 = int64_t;
using ui32 = uint32_t;
using ui64 = uint64_t;
namespace strdp {
const int N = 1e5;
int n, m, cnt, q;
int fa[N + 5];
struct node { int u, v, w, idx; } a[N + 5];
bool flg[N + 5];
struct node2 { int v, w; };
bool cmp(node x, node y) { return x.w < y.w; }
vector<node2> g[100005];
int fd(int x) { if (fa[x] == x) return x; return fa[x] = fd(fa[x]); }
void jn(int x, int y) { fa[fd(x)] = fd(y); }
int kruskal() {
int res = 0;
for (int i = 1; i <= m; i++) {
int u = fd(a[i].u), v = fd(a[i].v);
if (u != v) {
flg[i] = 1;
g[a[i].u].push_back({a[i].v, a[i].w});
g[a[i].v].push_back({a[i].u, a[i].w});
fa[u] = v; res += a[i].w;
if (++cnt == n - 1) return res;
}
}
}
int f[N + 5][21], dep[N + 5], res[N + 5][21];
bool vis[N + 5];
void dfs1(int x, int fa) {
vis[x] = 1; dep[x] = dep[fa] + 1;
f[x][0] = fa; res[x][0] = LLONG_MAX;
for (int i = 1; i <= 20; i++) {
f[x][i] = f[f[x][i - 1]][i - 1];
res[x][i] = LLONG_MAX;
}
for (auto u : g[x]) {
if (u.v != fa) dfs1(u.v, x);
}
}
int lca(int x, int y) {
if (dep[x] < dep[y]) swap(x, y);
for (int i = 20; i >= 0; i--) {
if (dep[f[x][i]] >= dep[y]) {
x = f[x][i];
}
}
if (x == y) return x;
for (int i = 20; i >= 0; i--) {
if (f[x][i] != f[y][i]) {
x = f[x][i];
y = f[y][i];
}
}
return f[x][0];
}
void update(int u, int v, int w) {
int l = lca(u, v);
for (int i = u; dep[i] > dep[l]; ) {
int j = f[i][0];
res[i][0] = min(res[i][0], w);
i = j;
}
for (int i = v; dep[i] > dep[l]; ) {
int j = f[i][0];
res[i][0] = min(res[i][0], w);
i = j;
}
}
int ans[N + 5];
void main() {
cin >> n >> m;
for (int i = 1; i <= n; i++) fa[i] = i;
for (int i = 1; i <= m; i++) {
int u, v, w;
cin >> u >> v >> w;
a[i] = {u, v, w, i};
}
sort(a + 1, a + m + 1, cmp);
int s = kruskal();
dfs1(1, 0);
for (int i = 1; i <= m; i++) if (!flg[i]) update(a[i].u, a[i].v, a[i].w);
for (int i = 20; i >= 1; i--) {
for (int j = 1; j <= n; j++) {
res[j][i - 1] = min(res[j][i - 1], res[j][i]);
if (f[j][i - 1] != i) res[f[j][i - 1]][i - 1] = min(res[f[j][i - 1]][i - 1], res[j][i]);
}
}
for (int i = 1; i <= m; i++) {
if (!flg[i]) ans[a[i].idx] = s;
else {
if (dep[a[i].u] < dep[a[i].v]) swap(a[i].u, a[i].v);
if (res[a[i].u][0] == LLONG_MAX) ans[a[i].idx] = -1;
else ans[a[i].idx] = s - a[i].w + res[a[i].u][0];
}
}
for (int i = 1; i <= m; i++) cout << ans[i] << "\n";
}
}
i32 main() {
int t = 1;
// cin >> t;
while (t--) strdp::main();
return 0;
}
相关推荐
评论
共 2 条评论,欢迎与作者交流。
正在加载评论...