本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作。
本文作者:ljh2000
作者博客:http://www.cnblogs.com/ljh2000-jump/
转载请注明出处,侵权必究,保留最终解释权!
题目链接:BZOJ3575
正解:SPFA+堆
解题报告:
考虑我不可能每次删掉当前边之后再跑一遍最短路,那我必须想办法优化我的删边+求得最短路过程。
考虑删边之后,当前的从1到n的最短路只能是从1出发,在最短路径上走一段,再走一段非最短路,最后回到最短路径上。
那么我如果强制不走当前边,在跑最短路的过程中,我只要发现走到了一个最短路径上的点上时,就可以用当前的距离更新一下ans。
我如果用堆保存一下我是走到哪个点导致的更新ans的话,就可以在以后反复调用,保证全局最优了。
注意每次跑SPFA无需清空dis,因为从左往右做的时候,dis显然递减(想一想最短路的松弛操作),但是到达最短路上的点的标记必须清空!
//It is made by ljh2000 #include <iostream> #include <cstdlib> #include <cstring> #include <cstdio> #include <cmath> #include <algorithm> #include <ctime> #include <vector> #include <queue> #include <map> #include <set> #include <string> #include <complex> using namespace std; typedef long long LL; typedef long double LB; typedef complex<double> C; const double pi = acos(-1); const int MAXN = 100011; const int MAXM = 200011; const int inf = (1<<30)-1; int n,m,L,ecnt,first[MAXN],to[MAXM],next[MAXM],w[MAXM],head,tail,top,stack[MAXN]; int a[MAXN],f[MAXN],g[MAXN],pos[MAXN],b[MAXN],dis[MAXN],dui[MAXN*40]; bool vis[MAXN],in[MAXN]; struct node{ int dis,x; inline bool operator < (const node &a) const { return a.dis<dis; } }tmp,c[MAXN]; priority_queue<node>Q; inline void link(int x,int y,int z){ next[++ecnt]=first[x]; first[x]=ecnt; to[ecnt]=y; w[ecnt]=z; } inline int getint(){ int w=0,q=0; char c=getchar(); while((c<'0'||c>'9') && c!='-') c=getchar(); if(c=='-') q=1,c=getchar(); while (c>='0'&&c<='9') w=w*10+c-'0',c=getchar(); return q?-w:w; } inline void SPFA(int inix,int iniw,int duan,int id){//dis数组不用清空,肯定是单调递减的... dis[inix]=iniw; head=tail=0; vis[inix]=1; dui[++tail]=inix; for(int i=1;i<=L+1;i++) in[i]=0;//需要清空!因为下次可能会更优! int u; top=0; while(head<tail) { head++; u=dui[head]; vis[u]=0; for(int i=first[u];i;i=next[i]) { if(i==duan) continue;//强制不走这条边 int v=to[i]; if(pos[v]>id) {//在最短路上的点不用再丢入队列中更新了 if(!in[pos[v]]) { in[pos[v]]=1; stack[++top]=v; c[v].dis=dis[u]+w[i]+g[pos[v]]/*!!!*/; c[v].x=pos[v]; } else c[v].dis=min(c[v].dis,dis[u]+w[i]+g[pos[v]]); } else { if(dis[v]>dis[u]+w[i]) { dis[v]=dis[u]+w[i]; if(!vis[v]) { vis[v]=1; dui[++tail]=v; } } } } } //加入堆中,方便调用全局最优 while(top>0) Q.push(c[stack[top]]),top--; } inline void work(){ n=getint(); m=getint(); L=getint(); int x,y,z; for(int i=1;i<=m;i++) { x=getint(); y=getint(); z=getint(); link(x,y,z); } b[1]=pos[1]=1; for(int i=1;i<=L;i++) { a[i]=getint(); b[i+1]=to[a[i]]; pos[to[a[i]]]=i+1; } for(int i=1;i<=L;i++) f[i+1]=f[i]+w[a[i]]; for(int i=L;i>=1;i--) g[i]=g[i+1]+w[a[i]]; for(int i=1;i<=n;i++) dis[i]=inf; for(int i=1;i<=L;i++) { SPFA(b[i],f[i],a[i],i); while(!Q.empty() && Q.top().x<=i)//需要比较的是pos! in[Q.top().x]=0,Q.pop(); if(Q.empty()) puts("-1"); else printf("%d ",Q.top().dis); } } int main() { work(); return 0; }