题链
[P5304 GXOI/GZOI2019]旅行者 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
分析
首先显然求出所有的被标记的点出发的最短路
再建反图求出所有被标记的点出发的最短路
显然每个被标记的点都有自己的管辖范围(在管辖范围中的点距离该点最近)
假设最后答案是\((u,v)\),则显然对于\((u,v)\)最短路径上的点,都被\(u\)或\(v\)管辖(否则可以找到另外一对答案更小的点),且存在一个分界点使得分界点左边的点都归\(u\)管,右边的点都归\(v\)管,所以枚举分界边即可
#include<bits/stdc++.h>
#define ll long long
const ll INF=1e18;
using namespace std;
const int N=1e5+5;
int n,m,K,a[N];
struct B{int v; ll w;};
inline bool operator >(B i,B j) {
return i.w>j.w;
}
priority_queue<B,vector<B>,greater<B> >Q;
struct A{
vector<B>V[N];bool fl[N]; ll d[N]; int f[N];
void clear() {
for(int i=1;i<=n;i++) V[i].clear();
}
void dij() {
for(int i=1;i<=n;i++) {
fl[i]=0,d[i]=INF,f[i]=0;
}
for(int i=1;i<=K;i++) {
f[a[i]]=a[i];
Q.push((B){a[i],d[a[i]]=0});
}
while(!Q.empty()) {
while(!Q.empty()&&fl[Q.top().v]) Q.pop();
if(Q.empty()) break;
int u=Q.top().v; fl[u]=1;
for(B v:V[u]) {
if(d[v.v]>d[u]+v.w) {
f[v.v]=f[u];
Q.push((B){v.v,d[v.v]=d[u]+v.w});
}
}
}
}
} tu1,tu2;
int main() {
int T; scanf("%d",&T);
while(T--) {
scanf("%d%d%d",&n,&m,&K);
tu1.clear(),tu2.clear();
for(int i=1;i<=m;i++) {
int u,v,k; scanf("%d%d%d",&u,&v,&k);
tu1.V[u].push_back((B){v,k});
tu2.V[v].push_back((B){u,k});
}
for(int i=1;i<=K;i++) {
scanf("%d",&a[i]);
}
tu1.dij(); tu2.dij();
ll ans=INF;
for(int i=1;i<=n;i++) {
for(B v:tu1.V[i]) {
if(tu1.f[i]!=tu2.f[v.v]) ans=min(ans,tu1.d[i]+tu2.d[v.v]+v.w);
}
}
printf("%lld\n",ans);
}
return 0;
}