题解:P11321 [NOISG 2020 Qualification] Relay Marathon
Solution
先考虑子任务
对剩下的关键点跑多源最短路。由超级源点对关键点连边权为
考虑最近的两个关键点之间的路径一定经过两个块的交界处,所以枚举边
考虑两对点怎么做。易证答案中的四个点中,必然有两个是距离最近的(或者你可以理解为就是子任务
时间复杂度在 Dijkstra 和排序,为
Code
#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;
}