专栏文章

题解:P11321 [NOISG 2020 Qualification] Relay Marathon

P11321题解参与者 2已保存评论 2

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
2 条
当前快照
1 份
快照标识符
@miojj43x
此快照首次捕获于
2025/12/02 20:14
3 个月前
此快照最后确认于
2025/12/02 20:14
3 个月前
查看原文

Solution

先考虑子任务 33 怎么做。首先路径 121\to 2 必选,只需要考虑剩下的关键点中选择哪两个。
对剩下的关键点跑多源最短路。由超级源点对关键点连边权为 00 的边,跑 dijkstra。于是我们就能得到每个点 uu 离最近关键点的距离 disudis_u,也能得到每个点的最近关键点 bub_u,或者说,这个图被分成若干个块,每个块对应一个关键点,块内的点都距离这个关键点最近。
考虑最近的两个关键点之间的路径一定经过两个块的交界处,所以枚举边 ii,满足 buibvib_{u_i} \ne b_{v_i},求 disui+disvidis_{u_i}+dis_{v_i} 的最小值。
考虑两对点怎么做。易证答案中的四个点中,必然有两个是距离最近的(或者你可以理解为就是子任务 33 求得的点),所以我们有两种思路,一种是两个距离最近的关键点连一条边,剩下两个距离次近的再连一条边,这可以仿照子任务 33 求出;另一种是两个距离最近的关键点分别找一个关键点连边,找到两个关键点距离最近的两个点,简单枚举即可。
时间复杂度在 Dijkstra 和排序,为 O(nlogn)O(n\log n)

Code

CPP
#include <bits/stdc++.h>
#define PII pair<int,int>
using namespace std;
const int N = 2e5+5,S = 2e5+4;
int n,m,k,a[N],dis[5][N],pre[N],u[3000005],v[3000005],w[3000005],x,y,mmin=999999999,book[N];
bool vis[5][N];
struct node
{
	int v,w;
};
vector<node>vec[N];
priority_queue<PII,vector<PII>,greater<PII>>q;
PII o[N],p[N];
void dijkstra(int u,int k)
{
	memset(dis[k],0x3f,sizeof dis[k]);
	q.push({0,u});
	dis[k][u] = 0;
	while (!q.empty())
	{
		PII now = q.top();
		q.pop();
		if (vis[k][now.second]) continue;
		vis[k][now.second] = 1;
		for (node i: vec[now.second])
		{
			if (dis[k][i.v] > dis[k][now.second]+i.w)
			{
				dis[k][i.v] = dis[k][now.second]+i.w;
				
				if (now.second == S) pre[i.v] = i.v;
				else pre[i.v] = pre[now.second];
				q.push({dis[k][i.v],i.v});
			}
		}
	}
}
signed main()
{
	ios_base::sync_with_stdio(0),cin.tie(0),cout.tie(0);
	cin >> n >> m >> k;
	for (int i = 1; i <= m; i++)
	{
		cin >> u[i] >> v[i] >> w[i];
		vec[u[i]].push_back({v[i],w[i]});
		vec[v[i]].push_back({u[i],w[i]});
	}
	for (int i = 1; i <= k; i++)
	{
		cin >> a[i];
		book[a[i]] = 1;
		vec[S].push_back({a[i],0});
	}
	dijkstra(S,0);
	for (int i = 1; i <= m; i++)
		if (pre[u[i]] != pre[v[i]] && dis[0][u[i]]+dis[0][v[i]]+w[i] < mmin)
			mmin = dis[0][u[i]]+dis[0][v[i]]+w[i],x = pre[u[i]],y = pre[v[i]];
//	cout << x << ' ' << y << ' ' << mmin << '\n';
	dijkstra(x,1);
	dijkstra(y,2);
	int ans = 999999999;
	int cnt1 = 0,cnt2 = 0;
	for (int i = 1; i <= n; i++)
		if (book[i]) o[++cnt1] = {dis[1][i],i};
	sort(o+1,o+cnt1+1);
	for (int i = 1; i <= n; i++)
		if (book[i]) p[++cnt2] = {dis[2][i],i};
	sort(p+1,p+cnt2+1);
	if (cnt1 >= 4)
	{
		if (o[3].second == p[3].second) ans = min(o[3].first+p[4].first,o[4].first+p[3].first);
		else ans = o[3].first+p[3].first;
	}
	for (int i = 0; i < vec[S].size(); i++)
		if (vec[S][i].v == x || vec[S][i].v == y) vec[S][i].w = 999999999;
	dijkstra(S,3);
	int min1 = 999999999;
	for (int i = 1; i <= m; i++)
		if (pre[u[i]] != pre[v[i]] && dis[3][u[i]]+dis[3][v[i]]+w[i] < min1)
			min1 = dis[3][u[i]]+dis[3][v[i]]+w[i];
	cout << min(ans,mmin+min1);
	return 0;
}

评论

2 条评论,欢迎与作者交流。

正在加载评论...