P1967 [NOIP2013 提高组] 货车运输

发布时间 2023-09-24 21:17:22作者: 不o凡

P1967 [NOIP2013 提高组] 货车运输

因为可能成环,这样可能导致到达点的最小权值不一,所以用最小生成树的方法重新建图
然后我是利用倍增的思想建立从i点开始,到上面点的距离ff和最小权值ww
因为最小权值不好直接建立,所以不如最后统一建立
最后就是寻找最近公共祖先的模板了
一组hack:
cin
5 4
1 2 1
1 3 1
2 3 1
4 5 5
1
4 5
cout
5
注意这组数据,也就是说数据可能是森林,要遍历完所以数据,当时跳进坑了。

点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N = 5e5 + 10;
int n, m;
//链式前向星
int h[N], ne[N * 2], w[N * 2], to[N * 2],cnt;
void add(int a, int b,int c) {
	to[++cnt] = b;
	ne[cnt] = h[a];
	w[cnt] = c;
	h[a] = cnt;
}
//Kruskal最小生成树,改为最大
struct edge {
	int u, v, w;
	bool operator<(const edge& a)const {
		return w>a.w;
	}
}e[N];
int f[N];
int find(int x) {
	return f[x] == x ? x : f[x] = find(f[x]);
}
void Kruskal() {
	sort(e + 1, e + 1 + m);
	for (int i = 1; i <= n; i++) f[i] =i;
	for (int i = 1; i <= m; i++) {
		int x = find(e[i].u);
		int y = find(e[i].v);
		if (x != y) {
			f[x] = y;
			add(e[i].u, e[i].v, e[i].w);
			add(e[i].v, e[i].u, e[i].w);
		}
	}
}
//先遍历一遍,找好跳一个点的距离和权值
int ff[N][22], ww[N][22],dep[N],vis[N];
void dfs(int u, int father) {
	vis[u] = 1;
	dep[u] = dep[father] + 1;
	ff[u][0] = father;
	for (int i = h[u]; i; i = ne[i]) {
		int v = to[i];
		if (v == father) continue;
		ww[v][0] = w[i];
		dfs(v, u);
	}
}
//最近公共祖先模板
int lca(int u, int v) {
	if (find(u) != find(v)) return -1;
	if (dep[u] < dep[v]) swap(u, v);
	int ans = 1e9;//初始化无穷
	for (int i = 19; i >= 0; i--) {
		if (dep[ff[u][i]]>= dep[v]) {
			ans = min(ans, ww[u][i]);//维护最小
			u = ff[u][i];
		}
	}
	if (v == u) return ans;//相遇直接返回
	for (int i = 19; i >= 0; i--) {
		if (ff[u][i] != ff[v][i]) {
			ans = min(ans, min(ww[u][i], ww[v][i]));//维护最小
			u = ff[u][i]; v = ff[v][i];
		}
	}
	return min(ans, min(ww[u][0], ww[v][0]));//维护最小
}

int main() {
	cin >> n >> m;
	for (int i = 1; i <= m; i++) {
		int x, y, z;
		cin >> x >> y >> z;
		e[i] = { x,y,z };
	}
	Kruskal();
	for (int i = 1; i <= n; i++) {//全部遍历
		if (!vis[i]) {
			dfs(i, 0);
		}
	}
	for (int i = 1; i <= 19; i++) {//统一计算
		for (int j = 1; j <= n; j++) {
			ff[j][i] = ff[ff[j][i - 1]][i - 1];
			ww[j][i] = min(ww[ff[j][i - 1]][i - 1], ww[j][i - 1]);
		}
	}
	int q;
	cin >> q;
	while (q--) {
		int x, y;
		cin >> x >> y;
		cout << lca(x, y) << '\n';
	}
}