• BZOJ3575: [Hnoi2014]道路堵塞


    BZOJ3575: [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的由交通部指定的最短路径上的道路的编号。
    2<N<100000,1<M<200000。所用道路长度大于0小于10000。

    Output

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

    Sample Input

    4 5 2
    1 2 2
    1 3 2
    3 4 4
    3 2 1
    2 4 3
    1 5

    Sample Output

    6
    6

    HINT

    数据已加强By Vfleaking,另2017.9.1再加数据一组,未重测。


    题解Here!
    这个题自从2017.9.2的最后一个AC记录之后就没有人再AC了。。。
    包括我也是。。。
    这种无脑加强数据的题目基本上就是废题了。。。
    当然,还可以到洛谷/LOJ上去搞搞事:

    洛谷P3238 [HNOI2014]道路堵塞

    LOJ#2209. 「HNOI2014」道路堵塞

    $BZOJ$质量真心差。。。

    正题:

    首先我们不可能每次删掉当前边之后再跑一遍最短路。。。

    那么我们必须想办法优化我的删边+求得最短路过程。

    我们考虑删边之后,当前的从$1$到$n$的最短路只能是从$1$出发,在最短路径上走一段,再走一段非最短路,最后回到最短路径上。

    这个应该能理解。

    那么如果我们强制让$SPFA$不走当前边,在跑最短路的过程中,我只要发现走到了一个最短路径上的点上时,就可以用当前的距离更新一下$ans$。

    我们可以用堆存走到哪个点导致了更新$ans$。

    这样就可以在以后反复调用,保证全局最优了。

    但是!每次跑$SPFA$无需清空$dis$,因为从左往右做的时候,$dis$显然递减!

    想一想最短路的松弛操作就应该知道怎么回事了。

    不过,到达最短路上的点的标记必须清空!

    然后就可以跑了。。。

    附代码:

    #include<iostream>
    #include<algorithm>
    #include<cstdio>
    #include<queue>
    #define MAXN 100010
    #define MAX ((1<<30)-1)
    using namespace std;
    int n,m,q;
    int top=0,stack[MAXN];
    int num[MAXN],t[MAXN],pos[MAXN],f[MAXN],g[MAXN];
    int head[MAXN],path[MAXN];
    bool vis[MAXN],used[MAXN];
    struct Graph{
    	int next,to,w;
    }a[MAXN<<1];
    struct node{
    	int x,dis;
    	bool operator <(const node &p)const{
    		return dis>p.dis;
    	}
    }b[MAXN];
    priority_queue<node> heap;
    inline int read(){
    	int date=0,w=1;char c=0;
    	while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();}
    	while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();}
    	return date*w;
    }
    inline int relax(int u,int v,int w){
    	if(path[v]>path[u]+w){
    		path[v]=path[u]+w;
    		return 1;
    	}
    	return 0;
    }
    inline void add(int u,int v,int w,int c){
    	a[c].to=v;a[c].w=w;a[c].next=head[u];head[u]=c++;
    }
    void spfa(int s,int w,int id,int time){
    	int u,v;
    	queue<int> que;
    	for(int i=1;i<=q+1;i++)used[i]=false;
    	path[s]=w;
    	vis[s]=true;
    	top=0;
    	que.push(s);
    	while(!que.empty()){
    		u=que.front();
    		que.pop();
    		vis[u]=false;
    		for(int i=head[u];i;i=a[i].next){
    			if(i==id)continue;
    			v=a[i].to;
    			if(pos[v]>time){
    				if(!used[pos[v]]){
    					used[pos[v]]=true;
    					stack[++top]=v;
    					b[v].x=pos[v];
    					b[v].dis=path[u]+a[i].w+g[pos[v]];
    				}
    				else b[v].dis=min(b[v].dis,path[u]+a[i].w+g[pos[v]]);
    			}
    			else{
    				if(relax(u,v,a[i].w)&&!vis[v]){
    					vis[v]=true;
    					que.push(v);
    				}
    			}
    		}
    	}
    	while(top)heap.push(b[stack[top--]]);
    }
    void work(){
    	for(int i=1;i<=q;i++){
    		spfa(t[i],f[i],num[i],i);
    		while(!heap.empty()&&heap.top().x<=i){
    			used[heap.top().x]=false;
    			heap.pop();
    		}
    		if(heap.empty())printf("-1
    ");
    		else printf("%d
    ",heap.top().dis);
    	}
    }
    void init(){
    	int u,v,w;
    	n=read();m=read();q=read();
    	for(int i=1;i<=n;i++){path[i]=MAX;vis[i]=false;}
    	for(int i=1;i<=m;i++){
    		u=read();v=read();w=read();
    		add(u,v,w,i);
    	}
    	t[1]=pos[1]=1;
    	for(int i=1;i<=q;i++){
    		num[i]=read();
    		t[i+1]=a[num[i]].to;
    		pos[a[num[i]].to]=i+1;
    	}
    	for(int i=1;i<=q;i++)f[i+1]=f[i]+a[num[i]].w;
    	for(int i=q;i>=1;i--)g[i]=g[i+1]+a[num[i]].w;
    }
    int main(){
    	init();
    	work();
        return 0;
    }

    $Update ext{于}2019.3.3$:

    好像现在在$BZOJ$上可以过了。

    但是复杂度有点玄学啊。。。

    算了,复杂度$O( ext{能过})$。。。

    过了就好。。。

    各位巨佬千万别像我这个菜鸡一样。。。

  • 相关阅读:
    java 笔记(2) 接口作为引用数据类型
    linux 笔记(5)让vi或vim显示行数和不显示行数
    linux 笔记(4)Ubuntu 使用时vi编辑器时,不能使用backspace键来进行退格或者不能正常使用
    linux 笔记(3)sudo passwd 设置root用户的密码
    matlab笔记(1) 元胞结构cell2mat和num2cell
    linux 笔记(2) 目录直接强行删除rm -rf *(删除当前目录所有的内容)
    linux 笔记(1) ctrl+c,ctrl+z,ctrl+d
    C51单片机项目:红绿灯
    C51单片机项目:时钟
    java 笔记(1)在子类中,一定要访问父类的有参构造方法?
  • 原文地址:https://www.cnblogs.com/Yangrui-Blog/p/9589270.html
Copyright © 2020-2023  润新知