zoukankan      html  css  js  c++  java
  • BZOJ3575 [Hnoi2014]道路堵塞

    本文版权归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;
    }
    

      

  • 相关阅读:
    关于MySQL数据库中null的那些事
    Java集合之Collections 剖析
    字符串类
    C++标准库
    << 操作符
    操作符的重载
    类中的重载
    友元
    二阶构造模式
    静态成员函数
  • 原文地址:https://www.cnblogs.com/ljh2000-jump/p/6482774.html
Copyright © 2011-2022 走看看