zoukankan      html  css  js  c++  java
  • bzoj 3575: [Hnoi2014]道路堵塞

    Description

    A 国有N座城市,依次标为1到N。同时,在这N座城市间有M条单向道路,每条道路的长度是一个正整数。现在,A国交通部指定了一条从城市1到城市N的路径, 并且保证这条路径的长度是所有从城市1到城市N的路径中最短的。不幸的是,因为从城市1到城市N旅行的人越来越多,这条由交通部指定的路径经常发生堵塞。 现在A国想知道,这条路径中的任意一条道路无法通行时,由城市1到N的最短路径长度是多少。

    Input

    输入文件第一行是三个用空格分开的正整数N、M和L,分别表示城市数目、单向道路数目和交通部指定的最短路径包含多少条道路。
    按下来M行,每行三个用空格分开的整数a、b和c,表示存在一条由城市a到城市b的长度为c的单向道路。这M行的行号也是对应道路的编号,即其中第1行对 应的道路编号为1,第2行对应的道路编号为2,…,第M行对应的道路编号为M。最后一行为L个用空格分开的整数sp(1)…,,sp(L),依次表示从城 市1到城市N的由交通部指定的最短路径上的道路的编号。

    Output

    输出文件包含L行,每行为一个整数,第i行(i=1,2…,,L)的整数表示删去编号为sp(i)的道路后从城市1到城市N的最短路径长度。如果去掉后没有从城市1到城市N的路径,则输出一1。

    真的是连SPFA都不会...

    根据玄学猜想:删掉最短路上的一条边后的最短路一定是由三段组成:

    最短路上的一段 1--x,非最短路上的一段x--y,以及最短路上的一段y--n;

    然后对于每次删掉一条连接(u,v)的边我们就把u放入队列中,并强制不走删掉的那一条边,拿u来松弛其它点到1的最短路

    如果走到了最短路上的某个点x,并且该点在最短路上的标号比u大(在u后面),把这个点放入堆中即可

    这个我们只需要维护好两个数组,一个1到每个最短路上的点的距离,一个是每个最短路上的点到n的距离

    之后就可以愉快的跑SPFA了

    // MADE BY QT666
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #include<iostream>
    #include<queue>
    #include<cstring>
    using namespace std;
    typedef long long ll;
    const int N=700050;
    int gi()
    {
        int x=0,flag=1;
        char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-') flag=-1;ch=getchar();}
        while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
        return x*flag;
    }
    int head[N],to[N],nxt[N],c[N],cnt;
    int pre[N],pre2[N],id[N],to2[N],n,m,L;
    int a[N],vis[N],vis2[N],q[N*10],q2[N*10],dis[N];
    struct data{
        int id,dis;
        bool operator < (const data &a) const {return a.dis<dis;}
    }b[N];
    priority_queue<data>Q;
    void lnk(int x,int y,int z){
        to[++cnt]=y,c[cnt]=z,nxt[cnt]=head[x],head[x]=cnt;
    }
    void spfa(int x,int y,int z){
        dis[x]=pre[id[x]];int t=0,sum=1,tail=0;q[0]=x;q2[++tail]=x;
        vis[x]=1;
        for(int i=1;i<=L+1;i++) vis2[to2[i]]=0;
        while(t<sum){
    	int now=q[t++];vis[now]=0;
    	for(int i=head[now];i;i=nxt[i]){
    	    if(i!=y){
    		int u=to[i];
    		if(id[u]>z){
    		    if(!vis2[u]){
    			b[u].dis=dis[now]+c[i]+pre2[id[u]];
    			b[u].id=id[u];vis2[u]=1;
    			q2[++tail]=u;
    		     }
    		    else b[u].dis=min(b[u].dis,dis[now]+c[i]+pre2[id[u]]);
    		}
    		else{
    		    if(dis[u]>dis[now]+c[i]){
    			dis[u]=dis[now]+c[i];
    			if(!vis[u]) vis[u]=1,q[sum++]=u;
    		    }
    		}
    	    }
    	}
        }
        while(tail) Q.push(b[q2[tail]]),tail--;
    }
    int main(){
        n=gi(),m=gi(),L=gi();
        for(int i=1;i<=m;i++){
    	int x=gi(),y=gi(),z=gi();
    	lnk(x,y,z);
        }
        to2[1]=id[1]=1;
        for(int i=1;i<=L;i++){
    	a[i]=gi();
    	to2[i+1]=to[a[i]];
    	id[to[a[i]]]=i+1;
        }
        for(int i=1;i<=L;i++) pre[i+1]=pre[i]+c[a[i]];
        for(int i=L;i>=1;i--) pre2[i]=pre2[i+1]+c[a[i]];
        memset(dis,127,sizeof(dis));
        for(int i=1;i<=L;i++){
    	spfa(to2[i],a[i],i);
    	while(!Q.empty()&&Q.top().id<=i) Q.pop();
    	if(Q.empty()) puts("-1");
    	else printf("%d
    ",Q.top().dis);
        }
    }
    
  • 相关阅读:
    win10+vs2010 安装Silverlight 安装说明
    常用小方法
    .net 技术学习进阶
    NetMQ——推拉模式 Push-Pull
    NetMQ使用——发布订阅模式 Publisher-Subscriber
    NetMQ使用——请求响应模式 Request-Reply
    跨终端Web
    七大排序算法
    JDK线程池
    Redis为什么这么快
  • 原文地址:https://www.cnblogs.com/qt666/p/6657758.html
Copyright © 2011-2022 走看看