貨車運輸(LCA+最大生成樹)

wlesq發表於2024-03-17

貨車運輸
這題會有重邊,又因為求的是儘可能大的邊中的最小值,所以我們可以先用最大生成樹維護,如何用最大生成樹呢?可以用Kruskal和並查集,順便處理重邊,處理完重邊後,可以用倍增LCA求兩點之間的最大載重量
處理重邊時,必須把dis在x,y相同情況下大的排在前,以保證最優,用並查集find判斷是否是重邊
建完以後,有環圖便成了一棵樹

點選檢視程式碼
#include <bits/stdc++.h>
using namespace std;
const int N = 50010;
int n,m,q;
int a[N/5],cnt,head[N/5];
int d[N/5],f[N/5][23],fa[N/5];bool vis[N/5];
struct EDGE
{
	int from,to,next,w;
}edge[N*2];
struct ED
{
	int x,y,dis;
}e1[N];
bool cmp(ED a,ED b)
{
	return a.dis>b.dis;
}
void add(int u,int v,int w)
{
	edge[++cnt].from=u;
	edge[cnt].to=v;
	edge[cnt].next=head[u];
	edge[cnt].w=w;
	head[u]=cnt;
}
int find(int x)
{
	if(fa[x]!=x)
	{
		fa[x]=find(fa[x]);
	}
	return fa[x];
}
void kruskal()
{
	sort(e1+1,e1+1+m,cmp);
	for(int i=1;i<=n;i++)fa[i]=i;
	for(int i=1;i<=m;i++)
	{
		int x=find(e1[i].x),y=find(e1[i].y);
		if(x==y)continue;
		fa[y]=x;
		add(e1[i].x,e1[i].y,e1[i].dis);add(e1[i].y,e1[i].x,e1[i].dis);
	}
	return;
}
int dis[N/5][23];
void dfs(int x)
{
	vis[x]=1;
	for(int i=head[x];i;i=edge[i].next)
	{
		int to=edge[i].to;
		if(vis[to])continue;
		dis[to][0]=edge[i].w;
		d[to]=d[x]+1;
		f[to][0]=x;
		dfs(to);
		
	}
}
void dfs_init()
{
	for(int j=1;j<23;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=INT_MAX;
	if(d[x]<d[y])swap(x,y);
//	int D=d[x]-d[y];
	for(int i=22;i>=0;i--)
	{
		if(d[f[x][i]]>=d[y])//i&
		{
			ans=min(ans,dis[x][i]),x=f[x][i];
//			cout<<x<<endl;
		}
	}
	if(x==y)return ans;
	for(int i=22;i>=0;i--)
	{
		if(f[x][i]!=f[y][i])
		{
			ans=min({ans,dis[x][i],dis[y][i]});
			x=f[x][i];
			y=f[y][i];
		}
	}
	ans=min({ans,dis[x][0],dis[y][0]});//不要忘記自身比較,否則會少情況
	return ans;
}
int main()
{
	scanf("%d%d",&n,&m);
	int x,y,z;
//	memset(dis,0x3f,sizeof(dis));
//	for(int i=1;i<=n;i++)
//		for(int j=0;j<23;j++)dis[i][j]=INT_MAX;
	for(int i=1;i<=m;i++)
	{
		scanf("%d%d%d",&e1[i].x,&e1[i].y,&e1[i].dis);
	}
	kruskal();
	scanf("%d",&q);
	for(int i=1;i<=n;i++)
	if(!vis[i])
	{	
		f[i][0]=i;
		d[i]=1;
		dfs(i);
		dis[i][0]=INT_MAX;
	}
	dfs_init();
//	for(int i=1;i<=n;i++)cout<<dis[i][0]<<" ";
//	cout<<endl;
	for(int i=1;i<=q;i++)
	{
		scanf("%d%d",&x,&y);
		int rx=find(x);int ry=find(y);
		if(rx!=ry)
		{
			printf("-1\n");
		}else
		{
//			cout<<x<<" "<<y<<endl;
			printf("%d\n",lca(x,y));
		}
	}
	return 0;
}
/*
4 4
1 2 4
2 3 3
3 1 1
1 2 5
3
1 3
1 4
1 3
*/

相關文章