洛谷 - P1967 货车运输

最大生成树+lca。
参考资料

思路

首先便是想到了Floyd的暴力方法,状态转移方程也不难推出:w[i][j]=max(w[i][j], min(w[i][k],w[k][j]));但是n3次方时间复杂度和n2的空间复杂度是显然不可取的。
于是我们思考,可以发现有一些权值较小的边是不会被走过的。正如样例中的第三条边,就算有其他的很多条边,这条边无论如何也是不会被走过的。于是我们想到了可以将图中这样的边去掉,按照这个思路我们便想到了构造最大生成树,将其余的边去除。
得到了这样一个树之后,我们便考虑如何求出两个节点之间最小边权的最大值(即为题中的最大载重),因为这两点之间的路径是唯一的,我们只需要找出这条路径便可以得到答案。我们可以通过LCA来做到这一点,先从每一个根节点进行搜索,求出节点深度等信息,然后利用这些信息进行树上倍增。
于是我们可以得出大体思路:首先重新建图,构造出最大生成树,然后在最大生成树上求LCA来回答询问。

代码

最可恶的是忘换行了……

#include<bits/stdc++.h>
#define INF 2000000000
using namespace std;
struct bian1 {
	int x,y,z;
} bn1[50005];
struct bian2 {
	int to,next,w;
} bn2[100005];
int cnt,n,m,head[10005],deep[10005],f[10005],fa[10005][21],w[10005][21];
bool vis[10005];
void adlln(int from, int to, int w){
	bn2[++cnt].next=head[from];
	bn2[cnt].to=to;
	bn2[cnt].w=w;
	head[from]=cnt;
	return;
}
bool CMP(bian1 x, bian1 y){
	return x.z>y.z;
}

int find(int x){
	if(f[x]!=x)f[x]=find(f[x]);
	return f[x];
}
void kruskal(){
	sort(bn1+1, bn1+m+1, CMP);
	for(int i=1;i<=n;i++)f[i]=i;
	for(int i=1;i<=m;i++){
		if(find(bn1[i].x)!=find(bn1[i].y)){
			f[find(bn1[i].x)]=find(bn1[i].y);
			adlln(bn1[i].x, bn1[i].y, bn1[i].z);
			adlln(bn1[i].y, bn1[i].x, bn1[i].z);
		}
	}
	return;
}
void dfs(int node){
	vis[node]=true;
	for(int i=head[node];i;i=bn2[i].next){
		int to=bn2[i].to;
		if(vis[to])continue;
		deep[to]=deep[node]+1;
		fa[to][0]=node;
		w[to][0]=bn2[i].w;
		dfs(to);
	}
	return;
}

int lca(int x, int y){
	if(find(x)!=find(y))return -1;
	int ans=INF;
	if(deep[x]>deep[y])swap(x,y);
	for(int i=20;i>=0;i--){
		if(deep[fa[y][i]]>=deep[x]){
			ans=min(ans, w[y][i]);
			y=fa[y][i];
		}
	}
	if(x==y)return ans;
	for(int i=20;i>=0;i--)
		if(fa[x][i]!=fa[y][i]){
			ans=min(ans, min(w[x][i], w[y][i]));
			x=fa[x][i];
			y=fa[y][i];
		}
	ans=min(ans, min(w[x][0], w[y][0]));
	return ans;
}
int main(){
	int x,y,z,q;
	ios::sync_with_stdio(0);
	cin.tie(0);   
	cout.tie(0);
	cin>>n>>m;
	for(int i=1;i<=m;i++)cin>>bn1[i].x>>bn1[i].y>>bn1[i].z;
	kruskal();
	for(int i=1;i<=n;i++){
		if(!vis[i]){ 
			deep[i]=1;
			dfs(i);
			fa[i][0]=i;
			w[i][0]=INF;
		}
	}
	for(int i=1;i<=20;i++){
		for(int j=1;j<=n;j++){
			fa[j][i]=fa[fa[j][i-1]][i-1];
			w[j][i]=min(w[j][i-1], w[fa[j][i-1]][i-1]);
		}
	}
	cin>>q;
	for(int i=1;i<=q;i++){
		cin>>x>>y;
		cout<<lca(x,y)<<'\n';
	}
	return 0;
}
posted @   yzc_is_SadBee  阅读(1)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】

阅读目录(Content)

此页目录为空

点击右上角即可分享
微信分享提示