BZOJ3732 Network

题目描述

给你 \(N\) 个点的无向图 ( \(1 \le N \le 15,000\) ),记为:\(1…N\)

图中有 \(M\) 条边 ( \(1 \le M \le 30,000\) ) ,第 \(j\) 条边的长度为: \(d_j ( 1 \le d_j \le 1,000,000,000)\).

现在有 \(K\) 个询问 (\(1 \le K \le 20,000\))。
每个询问的格式是:A B,表示询问从 \(A\) 点走到 \(B\) 点的所有路径中,最长的边最小值是多少?

思路

本题与P1967 [NOIP2013 提高组] 货车运输互为双倍经验。

一个是求最短边最长,一个是求最长边最短。

只要用Kruskal求出最小生成树,然后就倍增LCA询问就好了。时间复杂度只有 \(O(n\log n)\).

#include <bits/stdc++.h>
#define int long long
using namespace std;
int n, m, p;
struct node1 {
    int from, to, val;
} a1[500001];
struct node2 {
    int from, to, val;
} a2[100001];
int size, head[30005];
void add(int x, int y, int z) {
    a2[++size].to = y, a2[size].val = z;
    a2[size].from = head[x], head[x] = size;
}
int dep[30005];
int fa[30005];
int f[30005][33], dis[30005][33];
bool v[30005];
bool cmp(node1 x, node1 y) { return x.val < y.val; }
int find(int x) {
    if (x == fa[x])
        return x;

    return fa[x] = find(fa[x]);
}
void dfs(int now) {
    for (int i = head[now]; i; i = a2[i].from) {
        int u = a2[i].to;

        if (!v[u]) {
            v[u] = 1;
            dep[u] = dep[now] + 1;
            dis[u][0] = a2[i].val;
            f[u][0] = now;
            dfs(u);
        }
    }
}
int lca(int x, int y) {
    int ans = 0;

    if (dep[x] < dep[y])
        swap(x, y);

    for (int i = 20; i >= 0; i--) {
        if (dep[f[x][i]] >= dep[y]) {
            ans = max(ans, dis[x][i]);
            x = f[x][i];
        }
    }

    if (x == y)
        return ans;

    for (int i = 20; i >= 0; i--) {
        if (f[x][i] != f[y][i]) {
            ans = max(ans, max(dis[x][i], dis[y][i]));
            x = f[x][i];
            y = f[y][i];
        }
    }

    return ans = max(ans, max(dis[x][0], dis[y][0]));
}
signed main() {
    cin >> n >> m >> p;

    for (int i = 1; i <= m; i++) {
        int x, y, z;
        cin >> x >> y >> z;
        a1[i].from = x, a1[i].to = y;
        a1[i].val = z;
    }

    sort(a1 + 1, a1 + m + 1, cmp);

    for (int i = 1; i <= n; i++) fa[i] = i;

    for (int i = 1; i <= m; i++) {
        int u = find(a1[i].from), w = find(a1[i].to);

        if (u != w) {
            fa[u] = w;
            add(a1[i].from, a1[i].to, a1[i].val);
            add(a1[i].to, a1[i].from, a1[i].val);
        }
    }

    for (int i = 1; i <= n; i++) {
        if (!v[i]) {
            dep[i] = 1;
            v[i] = 1;
            dfs(i);
            dis[i][0] = 0;
            f[i][0] = i;
        }
    }

    for (int i = 1; i <= 20; i++) {
        for (int j = 1; j <= n; j++) {
            f[j][i] = f[f[j][i - 1]][i - 1];
            dis[j][i] = max(dis[j][i - 1], dis[f[j][i - 1]][i - 1]);
        }
    }

    // cin >> p;

    while (p--) {
        int x, y;
        cin >> x >> y;

        if (find(x) != find(y)) {
            cout << -1 << '\n';
        } else {
            cout << lca(x, y) << endl;
        }
    }
}
posted @ 2022-03-19 16:21  蒟蒻xiezheyuan  阅读(32)  评论(0编辑  收藏  举报