spfa,使用了支持修改的优先队列,防止 MLE。我试了一下,本地跑 hack 数据大约需要 20 秒,不知道有没有优化的方法。
#include<bits/stdc++.h>
#include<bits/extc++.h>
using namespace __gnu_pbds;
struct Edge {
int u, v, w;
int f; // 是否在最短路上
} all[200005]; // 储存所有边
struct Edge2 {
int u, v, w;
int ne;
} e[200005]; // 储存不经过规定路线的边
int h[100005], idx;
void add(int u, int v, int w) {
e[++idx] = {u, v, w, h[u]};
h[u] = idx;
}
struct node {
int u, dis;
bool operator < (const node &x) const {
return dis > x.dis;
}
};
priority_queue<node>s;
priority_queue<node>::point_iterator tmp[100005];
int tmpf[100005];
int n, m, l, dis[100005], disn[200005];
int q[100005], qh, qt;
int vis[100005];
int a[200005]; // 最短路的第 i 条边的索引
int pid[100005]; // 第 i 个点在最短路上的编号
void spfa(int st) {
q[0]=st, qh=-1, qt=0; // (qh, qt]
while(qh != qt) {
++qh;
if(qh>100000) qh=0;
int x=q[qh];
// if(q[qh+1] > q[qt]) std::swap(q[qh+1], q[qt]); // swap 玄学优化
vis[x]=0;
for(int i=h[x]; i; i=e[i].ne) {
int y=e[i].v;
if(dis[x]+e[i].w < dis[y]) {
dis[y] = dis[x]+e[i].w;
if(pid[y]) {
if(tmpf[pid[y]]) {
// 直接修改,防止 MLE
s.modify(tmp[pid[y]], {pid[y], dis[y]+disn[pid[y]]});
} else {
tmp[pid[y]] = s.push({pid[y], dis[y]+disn[pid[y]]});
tmpf[pid[y]]=1;
}
}
if(!vis[y]) {
vis[y]=1;
++qt;
if(qt>100000) qt=0;
q[qt]=y;
// if(q[qh+1] > q[qt]) std::swap(q[qh+1], q[qt]); // swap 玄学优化
}
}
}
}
}
int main() {
// freopen("hack.in", "r", stdin);
// freopen("hack.out", "w", stdout);
memset(dis, 0x3f, sizeof dis), dis[1]=0;
scanf("%d%d%d", &n, &m, &l);
for(int i=1; i<=m; i++) scanf("%d%d%d", &all[i].u, &all[i].v, &all[i].w);
for(int i=1; i<=l; i++) scanf("%d", &a[i]), all[a[i]].f=1, pid[all[a[i]].v]=i+1;
pid[all[a[1]].u]=1;
for(int i=1; i<=m; i++)
if(!all[i].f)
add(all[i].u, all[i].v, all[i].w);
for(int i=l; i; i--) disn[i]=disn[i+1]+all[a[i]].w;
spfa(1);
for(int i=1; i<=l; i++) {
while(!s.empty() && s.top().u<=i) tmpf[s.top().u]=0, s.pop();
printf("%d\n", s.empty()?-1:s.top().dis);
dis[all[a[i]].v] = dis[all[a[i]].u] + all[a[i]].w;
spfa(all[a[i]].v);
}
// printf("%d", clock());
return 0;
}