洛谷 P1967 货车运输

题面

题目描述

A 国有n座城市,编号从 1 到 n,城市之间有 m 条双向道路。每一条道路对车辆都有重量限制,简称限重。
现在有 q 辆货车在运输货物, 司机们想知道每辆车在不超过车辆限重的情况下,最多能运多重的货物。

输入格式

第一行有两个用一个空格隔开的整数 n,m,表示 A 国有 n 座城市和 m 条道路。
接下来 m 行每行三个整数 x, y, z每两个整数之间用一个空格隔开,表示从 x 号城市到 y 号城市有一条限重为 z 的道路。
注意:两座城市之间可能有多条道路 。接下来一行有一个整数 q,表示有 q 辆货车需要运货。
接下来 q 行,每行两个整数 x,y之间用一个空格隔开,表示一辆货车需要从 x 城市运输货物到 y 城市,保证 $$x \neq y$$

输出格式

共有 q 行,每行一个整数,表示对于每一辆货车,它的最大载重是多少。
如果货车不能到达目的地,输出 -1。

想法

今天上午花了两个多小时搞出来的一道题,本来最开始想爆搜 + 贪心来做Floyd(暴力大法好),结果发现只有可怜的30分(QAQ),无奈只得好好看题分析。题中说到,要求的是每辆货车的最大载重量,所以说我们是不会选择可以到达相同地点边权小的路径的,所以说我们可以将这些边删去(诶有点像最小生成树),但是这道题我们要求的不是最小生成树而是最大生成树,那么接下来就是在上进行操作了(又是一道树论题 ̄へ ̄),那么既然是树了,在一个树之间两个节点之间的路径是唯一的,那么我们只需要求出这条路径上最小的边权,那么我们可以想到什么,对,爆搜(划去),咳LCA,在LCA的同时也要注意维护最小边权。我们来总结一下,首先要建图,生成最大生成树,然后进行LCA求得最小边权。

代码

#include
#include
#include
#define INF 0x3f3f3f
using namespace std;
int n, m, q, cnt = 0;
bool vis[50010];
int fu[50010][22], w[50010][22];
int fa[10010], head[10010], depth[10010];
struct edge1{
	int u, v, w;
}e1[50010];
struct edge2{
	int w, to, next;
}e2[50010 << 1];
inline int read(){
	int s = 0;
	char ch = getchar();
	while(ch < '0' || ch > '9') ch = getchar();
	while(ch >= '0' && ch <= '9'){s = s * 10 + ch - '0'; ch = getchar();}
	return s;
}
bool cmp(edge1 a, edge1 b){return a.w > b.w;}
int find(int x){
	if(x != fa[x]) fa[x] = find(fa[x]);
	return fa[x];
}
void add(int u, int v, int w){
	e2[++cnt].next = head[u];
	e2[cnt].to = v;
	e2[cnt].w = w;
	head[u] = cnt;
}
void kruskal(){
	sort(e1 + 1, e1 + m + 1, cmp);
	for(int i = 1; i <= n; i++) fa[i] = i;
	for(int i = 1; i <= m; i++)
		if(find(e1[i].u) != find(e1[i].v)){
			fa[find(e1[i].u)] = find(e1[i].v);
			add(e1[i].u, e1[i].v, e1[i].w);
			add(e1[i].v, e1[i].u, e1[i].w);
		}
}
void dfs(int now){
	vis[now] = true;
	for(int i = head[now]; i; i = e2[i].next){
		int to = e2[i].to;
		if(vis[to]) continue;
		depth[to] = depth[now] + 1;
		w[to][0]  = e2[i].w;
		fu[to][0] = now;
		dfs(to);
	}
}
int LCA(int u, int v){
	if(find(u) != find(v)) return -1;
	int ans = INF;
	if(depth[u] > depth[v]) swap(u, v);
	for(int i = 20; i >= 0; i--)
		if(depth[fu[v][i]] >= depth[u]){
			ans = min(ans, w[v][i]);
			v = fu[v][i];
		}
	if(u == v) return ans;
	for(int i = 20; i >= 0; i--)
		if(fu[u][i] != fu[v][i]){
			ans = min(ans, min(w[u][i], w[v][i]));
			u = fu[u][i];
			v = fu[v][i];
		}
	ans = min(ans, min(w[u][0], w[v][0]));
	return ans;
}
int main(){
	n = read(); m = read();
	for(int i = 1; i <= m; i++){
		int x, y, z; 
		x = read(); y = read(); z = read();
		e1[i].u = x; e1[i].v = y; e1[i].w = z;
	}
	kruskal();
	for(int i = 1; i <= n; i++)
		if(!vis[i]){
			depth[i] = 1;
			dfs(i);
			fu[i][0] = i;
			w[i][0] = INF;
		}
	for(int i = 1; i <= 20; i++)
		for(int j = 1; j <= n; j++){
			fu[j][i] = fu[fu[j][i - 1]][i - 1];
			w[j][i] = min(w[j][i - 1], w[fu[j][i - 1]][i - 1]);
		}
	q = read();
	for(int i = 1; i <= q; i++){
		int u, v; u = read(); v = read();
		printf("%d\n", LCA(u, v));
	}
	return 0;
}
posted @ 2020-11-13 16:40  summitsoul  阅读(119)  评论(0编辑  收藏  举报