洛谷P1967 货车运输

(large{题目链接})
(\)
(Large extbf{Solution: } large{注意到两地之间的路径可能有多条,又要使路径上的边权最小最大,想到最大生成树。\先建树,然后树上倍增即可。\值得注意的是,图中所有点不一定联通,所以搜索时要谨慎。})

(Large extbf{Code: })

#include <bits/stdc++.h>
#define gc() getchar() 
#define rep(i, a, b) for (int i = (a); i <= (b); ++i)
using namespace std;
const int N = 1e4 + 5;
const int M = 5e4 + 5;
const int inf = 0x7fffffff;
int n, m, cnt, f[N], h[N], head[N], vis[N], lg[N], dep[N], Min[N][20], fa[N][20];

struct Edge {
	int fro, to, val;
}E[M];

struct EDGE {
	int to, next, val;	
}e[N << 1];

inline int read() {
	int x = 0;
	char ch = gc();
	while (!isdigit(ch)) ch = gc();
	while (isdigit(ch)) x = x * 10 + ch - '0', ch = gc();
	return x; 
}

inline void add(int x, int y, int w) {
	e[++cnt].to = y;
	e[cnt].next = head[x];
	e[cnt].val = w;
	head[x] = cnt;
}

inline int find(int x) {
	if (x == f[x]) return x;
	return f[x] = find(f[x]);
}

inline bool cmp(Edge a, Edge b) {
	return a.val > b.val;	
}

inline void Kruskal() {
	rep(i, 1, n) f[i] = i;
	sort(E + 1, E + m + 1, cmp);
	int tot = 0;
	for (int i = 1; i <= m; ++i) {
		int u = find(E[i].fro), v = find(E[i].to);
		if (u != v) f[v] = u, ++tot, add(E[i].fro, E[i].to, E[i].val), add(E[i].to, E[i].fro, E[i].val);
		if (tot == n - 1) break;
	}
	return;
}

inline void dfs(int x, int fat, int w) {
	vis[x] = 1;
	fa[x][0] = fat;
	Min[x][0] = w;
	dep[x] = dep[fat] + 1;
	for (int i = 1; (1 << i) <= dep[x]; ++i) {
		fa[x][i] = fa[fa[x][i - 1]][i - 1];
		Min[x][i] = min(Min[x][i - 1], Min[fa[x][i - 1]][i - 1]);
	}
	for (int i = head[x]; i ; i = e[i].next) if (e[i].to != fat) dfs(e[i].to, x, e[i].val);
}

inline int sol(int x, int y) {
	if (find(x) != find(y)) return -1;
	int ans = inf;
	if (dep[x] < dep[y]) swap(x, y);
	while (dep[x] > dep[y]) ans = min(ans, Min[x][lg[dep[x] - dep[y]]]), x = fa[x][lg[dep[x] - dep[y]]];
	if (x == y) return ans;
	for (int i = lg[dep[x]]; i >= 0; --i) if (fa[x][i] != fa[y][i]) ans = min(ans, min(Min[x][i], Min[y][i])), x = fa[x][i], y = fa[y][i];
	ans = min(ans, min(Min[x][0], Min[y][0]));
	return ans;
}

int main() {
	n = read(), m = read();
	int x, y, w;
	rep(i, 2, n) lg[i] = lg[i >> 1] + 1;
	for (int i = 1; i <= m; ++i) E[i].fro = read(), E[i].to = read(), E[i].val = read();
	Kruskal();
	rep(i, 1, 20) rep(j, 1, n) Min[i][j] = inf;
	rep(i, 1, n)
		if (!dep[i]) {
			dep[i] = 0;
			dfs(i, 0, inf);
		}
	m = read();
	while (m--) {
		x = read(), y = read();
		if (!vis[x] || !vis[y]) { puts("-1"); continue; }
		printf("%d
", sol(x, y));
	}
	return 0;
}