链接
题目大意:
在一张网路上,每条边有一个权重w。
给多次询问x,y,求x到y的路径上最小w的最大值
思路:
容易想到路径一定存在于网络的最大生成树上。
在这颗树上,求两点间最小边权。
用倍增LCA即可完成。
code
cpp
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int MAXN = 1e5 + 5;
int n, m, q;
int head[MAXN], tot, tot2, Q[MAXN];
int dep[MAXN], f[MAXN][21], dis[MAXN][21];
struct Edge {
int fro, to, nxt, w;
} E[MAXN << 1], E2[MAXN << 1];
void add(int x, int y, int w) {
E[++ tot] = (Edge) {x, y, head[x], w};
head[x] = tot;
}
void add_(int x, int y, int w) {
E2[++ tot2] = (Edge) {x, y, head[x], w};
head[x] = tot2;
}
bool cmp(Edge x, Edge y) {
return x.w > y.w;
}
int Find(int x) {
if(Q[x] != x) return Q[x] = Find(Q[x]);
return x;
}
void dfs(int x, int fa) {
dep[x] = dep[fa] + 1;
f[x][0] = fa;
for(int i = head[x]; i; i = E2[i].nxt) {
int y = E2[i].to;
if(y == fa) continue;
dis[y][0] = E2[i].w;
dfs(y, x);
}
}
void krus() {
sort(E + 1, E + 1 + tot, cmp);
for(int i = 1; i <= n; i ++) Q[i] = i, head[i] = 0;
for(int i = 1; i <= tot; i ++) {
int x = E[i].fro, y = E[i].to;
if(Find(x) != Find(y)) {
Q[Find(x)] = Find(y);
add_(x, y, E[i].w), add_(y, x, E[i].w);
}
}
}
void RMQ() {
for(int j = 1; j <= 20; j ++)
for(int i = 1; i <= n; i ++)
f[i][j] = f[f[i][j - 1]][j - 1],
dis[i][j] = min(dis[i][j - 1], dis[f[i][j - 1]][j - 1]);
}
int lca(int x, int y) {
int ans = 1e9;
if(dep[x] < dep[y]) swap(x, y);
int t = dep[x] - dep[y], j = 20;
while(t) {
if(t >= (1 << j)) t -= 1 << j, ans = min(ans, dis[x][j]), x = f[x][j];
j --;
}
if(x == y) return ans;
for(int j = 20; j >= 0; j --)
if(f[x][j] != f[y][j]) ans = min(ans, min(dis[x][j], dis[y][j])), x = f[x][j], y = f[y][j];
return min(ans, min(dis[y][0], dis[x][0]));
}
int main() {
scanf("%d%d", &n, &m);
for(int i = 1; i <= m; i ++) {
int x, y, w;
scanf("%d%d%d", &x, &y, &w);
add(x, y, w), add(y, x, w);
}
krus();
for(int i = 1; i <= n; i ++)
if(!dep[i]) dfs(i, 0);
RMQ();
scanf("%d", &q);
while(q --) {
int x, y;
scanf("%d%d", &x, &y);
int ans = lca(x, y);
printf("%d\n", ans == 0 ? -1 : ans);
}
return 0;
}