CF609E Minimum spanning tree for each edge

CF609E Minimum spanning tree for each edge

水题

显然, 本来就在最小生成树里的边的 \(ans\) 就是最小生成树了.

如果不在最小生成树里, 那我们就给这条边的起点和终点在最小生成树上做一个 \(LCA\) , 然后顺便维护一下路径上的最大值, 用 \(ans\) 加上当前边的 \(dis\) 再减掉路径上的最大值就行了.

复杂度 \(O(n \log n)\)

\(code:\)

#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
const int N = 2e5 + 5, M = 4e5 + 5;
int n, m, fa[N], f[N][30], dep[N], d[N][30];
int tot, to[M], dis[M], nxt[M], head[N];
ll ans[N];
bool in[N];
struct Edge{
    int from, to, dis, id;
} edge[N];
int read() {
    int x = 0, f = 1;
    char ch = getchar();
    while (!isdigit(ch)) {
        if (ch == '-') f = -1;
        ch = getchar();
    }
    while (isdigit(ch)) {
        x = (x << 1) + (x << 3) + (ch ^ 48);
        ch = getchar();
    }
    return x * f;
}
bool cmp(Edge x, Edge y) {
    return x.dis < y.dis;
}
void add(int u, int v, int w) {
    to[++tot] = v, dis[tot] = w, nxt[tot] = head[u], head[u] = tot;
    to[++tot] = u, dis[tot] = w, nxt[tot] = head[v], head[v] = tot;
}
int get(int x) {
    if (x == fa[x]) return x;
    return fa[x] = get(fa[x]);
}
void dfs(int x, int father, int dist) {
    dep[x] = dep[father] + 1; f[x][0] = father; d[x][0] = dist;
    for (int i = 1; i <= 25; i++) {
        f[x][i] = f[f[x][i - 1]][i - 1];
        d[x][i] = max(d[x][i - 1], d[f[x][i - 1]][i - 1]);
    }
    for (int i = head[x]; i; i = nxt[i]) {
        int y = to[i], z = dis[i];
        if (y != father) dfs(y, x, z);
    }
}
int lca(int x, int y) {
    int tmp = -1e9;
    if (dep[x] < dep[y]) swap(x, y);
    for (int i = 25; i >= 0; i--) {
        if (dep[f[x][i]] >= dep[y]) {
            tmp = max(tmp, d[x][i]);
            x = f[x][i];
        }
        if (x == y) return tmp;
    }
    for (int i = 25; i >= 0; i--) {
        if (f[x][i] != f[y][i]) {
            tmp = max(tmp, max(d[x][i], d[y][i]));
            x = f[x][i], y = f[y][i];
        }
    }
    return max(tmp, max(d[x][0], d[y][0]));
}
int main() {
    n = read(), m = read();
    for (int i = 1; i <= m; i++) {
        int u = read(), v = read(), w = read();
        edge[i] = {u, v, w, i};
    }
    sort(edge + 1, edge + m + 1, cmp);
    for (int i = 1; i <= n; i++) fa[i] = i;
    ll tmp = 0;
    for (int i = 1; i <= m; i++) {
        if (tot >> 1 == n - 1) break;
        int x = get(edge[i].from), y = get(edge[i].to);
        if (x == y) continue;
        tmp += edge[i].dis; in[i] = 1; fa[x] = y;
        add(edge[i].from, edge[i].to, edge[i].dis);
    }
    dfs(edge[1].from, 0, 0);
    for (int i = 1; i <= m; i++) {
        int id = edge[i].id, u = edge[i].from, v = edge[i].to, w = edge[i].dis;
        if (in[i]) {
            ans[id] = tmp;
            continue;
        }
        else {
            ans[id] = tmp + w;
            ans[id] -= lca(u, v);
        }
    }
    for (int i = 1; i <= m; i++) printf("%lld\n", ans[i]);
    return 0;
}

注意一下, 返回路径上的最大值的时候记得 \(x, y\) 的都要返回, 因为可能不一样, 卡了我好久...

posted @ 2021-08-22 16:42  sshadows  阅读(14)  评论(0编辑  收藏  举报