P5304 [GXOI/GZOI2019] 旅行者 题解

P5304 [GXOI/GZOI2019] 旅行者

Description

给你一个 \(n\) 个点,\(m\) 条边的有向连通图,给出 \(k\) 个点的编号,让你求出这些点中距离最近的两点之间距离。

\(n\le 10^5,m\le 5\times 10^5\)

Solution

这题是一个十分经典的 trick —— 二进制分组

大概的思路类似于有源汇网络流,即建立一个超级源点和超级汇点,跑最短路。具体来说,把 \(k\) 个结点随机分到两个集合 \(s\)\(t\) 中,用一个 bool 数组来记录这 \(k\) 个点,如果编号为 \(i\) 的点在 \(s\) 中记为 \(0\),在 \(t\) 中记为 \(1\)

由于这个图是有向图,所以先从超级源点向所有 \(s\) 中的点连边,从 \(t\) 中的所有点向 \(t\) 连边跑 \(\log n\) 次最短路,再反过来跑 \(\log n\) 次最短路,最后所有最短路的最小值即为答案。

时间复杂度 \(O(Tn\log n\log k)\),可以通过。

#include<bits/stdc++.h>
#define int long long
using namespace std;
long long T,n,m,k,a[500005],ans;
priority_queue<pair<int,int>>q;
struct graph{
	long long tot,head[500005],id[500005],dis[500005];
	struct node{
		int from,to,w,nxt;
	}e[500005];
	inline void init(){
		tot=0;
		memset(head,0,sizeof(head));
		return;
	}
	inline void add(int u,int v,int w){
		e[++tot].from=u;
		e[tot].to=v;
		e[tot].w=w;
		e[tot].nxt=head[u];
		head[u]=tot;
		return;
	}
	inline void dijkstra(){
		for(int i=1;i<=500000;i++){
			dis[i]=LONG_LONG_MAX;
				id[i]=0;
		}
		for(int i=1;i<=k;i++){
			dis[a[i]]=0;
			id[a[i]]=a[i];
			q.push(make_pair(0,a[i]));
		}
		while(!q.empty()){
			int u=q.top().second;
			int d=-q.top().first;
			q.pop();
			if(d==dis[u]){
				for(int i=head[u];i;i=e[i].nxt){
					int v=e[i].to,w=e[i].w;
					if(dis[v]>d+w){
						dis[v]=d+w;
						id[v]=id[u];
						q.push(make_pair(-dis[v],v));
					}
				}
			}
		}
		return;
	}
}G[2];
signed main(){
	cin>>T;
	while(T--){
		cin>>n>>m>>k;
		G[0].init();
		G[1].init();
		for(int i=1;i<=m;i++){
			int u,v,w;
			cin>>u>>v>>w;
			if(u^v){
				G[0].add(u,v,w);
				G[1].add(v,u,w);
			}
		}
		for(int i=1;i<=k;i++){
			cin>>a[i];
		}
		G[0].dijkstra();
		G[1].dijkstra();
		ans=LONG_LONG_MAX;
		for(int u=1;u<=n;u++){
			for(int i=G[0].head[u];i;i=G[0].e[i].nxt){
				int v=G[0].e[i].to;
				int w=G[0].e[i].w;
				if(G[0].id[u]&&G[1].id[v]&&G[0].id[u]^G[1].id[v]){
					ans=min(ans,G[0].dis[u]+G[1].dis[v]+w);
				}
			}
		}
		cout<<ans<<endl;
	}
	return 0;
}
posted @ 2025-12-09 22:04  Creativexz  阅读(1)  评论(0)    收藏  举报