洛谷P1967 货车运输 题解 最大生成树+LCA

题目链接:https://www.luogu.com.cn/problem/P1967

解题思路:

  1. 先求最大生成树;
  2. 在用LCA求路径最小边。

示例代码:

#include <bits/stdc++.h>
using namespace std;
const int maxn = 10010, maxm = 100010;
int n, m, f[maxn];
void init() {
    for (int i = 1; i <= n; i ++) f[i] = i;
}
int func_find(int x) {
    return x == f[x] ? x : f[x] = func_find(f[x]);
}
void func_union(int x, int y) {
    int a = func_find(x), b = func_find(y);
    f[a] = f[b] = f[x] = f[y] = min(a, b);
}
struct E {
    int u, v, z;
} e[maxm];
bool cmp(E a, E b) {
    return a.z > b.z;
}
struct Edge {
    int u, v, z, nxt;
    Edge() {};
    Edge(int _u, int _v, int _z, int _nxt) { u = _u; v = _v; z = _z; nxt = _nxt; }
} edge[maxm];
int head[maxn], ecnt;
void init_e() {
    ecnt = 0;
    memset(head, -1, sizeof(int)*(n+1));
}
void addedge(int u, int v, int z) {
    edge[ecnt] = Edge(u, v, z, head[u]); head[u] = ecnt ++;
    edge[ecnt] = Edge(v, u, z, head[v]); head[v] = ecnt ++;
}
void kruskal() {
    init();
    init_e();
    sort(e, e+m, cmp);
    int cnt = 0;
    for (int i = 0; i < m; i ++) {
        int u = e[i].u, v = e[i].v;
        if (func_find(u) != func_find(v)) {
            cnt ++;
            func_union(u, v);
            addedge(u, v, e[i].z);
            if (cnt >= n-1) break;
        }
    }
}
int pa[maxn][15], zz[maxn][15], dep[maxn];
void dfs(int u, int p, int z) {
    dep[u] = dep[p] + 1;
    pa[u][0] = p;
    zz[u][0] = z;
    for (int i = 1; (1<<i) <= dep[u]; i ++) {
        pa[u][i] = pa[ pa[u][i-1] ][i-1];
        zz[u][i] = min(zz[u][i-1], zz[ pa[u][i-1] ][i-1]);
    }
    for (int i = head[u]; i != -1; i = edge[i].nxt) {
        int v = edge[i].v;
        if (v == p) continue;
        dfs(v, u, edge[i].z);
    }
}
/**
 lca(x,y): 返回x到y路径上最小边权
*/
int lca(int x, int y) {
    int ans = INT_MAX;
    if (dep[x] < dep[y]) swap(x, y);
    for (int i = 14; i >= 0; i --) {
        if (dep[ pa[x][i] ] >= dep[y]) {
            ans = min(ans, zz[x][i]);
            x = pa[x][i];
        }
        if (x == y) return ans;
    }
    for (int i = 14; i >= 0; i --) {
        if (pa[x][i] != pa[y][i]) {
            ans = min(ans, zz[x][i]);
            x = pa[x][i];
            ans = min(ans, zz[y][i]);
            y = pa[y][i];
        }
    }
    ans = min(ans, zz[x][0]);
    ans = min(ans, zz[y][0]);
    return ans;
}
int main() {
    cin >> n >> m;
    for (int i = 0; i < m; i ++) cin >> e[i].u >> e[i].v >> e[i].z;
    kruskal();
    memset(zz, 0x3f, sizeof(zz));
    dfs(1, 0, INT_MAX);
    int q, x, y;
    cin >> q;
    while (q --) {
        cin >> x >> y;
        if (func_find(x) != func_find(y)) cout << -1 << endl;
        else cout << lca(x, y) << endl;
    }
    return 0;
}
原文地址:https://www.cnblogs.com/quanjun/p/13812788.html