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;
}
}
}