[bzoj3575][最短路-SPFA]道路堵塞

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

题解

首先有一个性质
删去一条边之后走的边一定是
1走一些最短路边 然后走一些非最短路边 然后再走一堆最短路边到n
根据这个就可以搞事了
不妨先把所有最短路边删掉
枚举每条边依次加入可以跑的边中 每次就让当前这条边去跑spfa
比较好玩的就是这个dis不需要清空,一清空就稳的 n 2 n^2 n2了啊
因为你发现dis是单调不增的,所以完全可以直接在上面的基础跑
如果走到了一些在最短路上的点,就把当前这条路径扔进堆里,顺便记录一下最后没有跑的最短路边是哪一条
然后扫一遍就完事

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
#include<ctime>
#include<map>
#include<bitset>
#define LL long long
#define mp(x,y) make_pair(x,y)
#define pll pair<long long,long long>
#define pii pair<int,int>
using namespace std;
inline int read()
{
	int f=1,x=0;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
	return x*f;
}
int stack[20];
inline void write(int x)
{
	if(x<0){putchar('-');x=-x;}
    if(!x){putchar('0');return;}
    int top=0;
    while(x)stack[++top]=x%10,x/=10;
    while(top)putchar(stack[top--]+'0');
}
inline void pr1(int x){write(x);putchar(' ');}
inline void pr2(int x){write(x);putchar('\n');}
const int MAXM=200005;
const int MAXN=100005;
struct node{int x,y,c,next;}a[MAXM];int len,last[MAXN];
void ins(int x,int y,int c){len++;a[len].x=x;a[len].y=y;a[len].c=c;a[len].next=last[x];last[x]=len;}
int d[MAXN],n,m,L;
queue<int> li;
priority_queue<pii,vector<pii>,greater<pii> > heap;
bool is[MAXN],vis[MAXN],no[MAXM];

int fr[MAXN],ba[MAXN],lin[MAXM],s[MAXM],pre[MAXN],tot;

void spfa(int st)
{
	li.push(st);
	while(!li.empty())
	{
		int x=li.front();li.pop();vis[x]=false;
		for(int k=last[x];k;k=a[k].next)
		{
			int y=a[k].y;
			if(d[y]>d[x]+a[k].c&&(!no[k]))
			{
				d[y]=d[x]+a[k].c;
				if(is[y])
				{
					heap.push(mp(d[y]+ba[y],pre[y]));
//					printf("YES %d %d %d %d %d\n",st,x,y,d[y]+ba[y],pre[y]);
				}
				if(!vis[y])vis[y]=true,li.push(y);
			}
		}
	}
}
int main()
{
//	freopen("1.in","r",stdin);
	n=read();m=read();L=read();
	for(int i=1;i<=m;i++)
	{
		int x=read(),y=read(),c=read();
		ins(x,y,c);
	}
	for(int i=1;i<=L;i++)
	{
		no[lin[i]=read()]=true;
		s[++tot]=a[lin[i]].x;is[s[tot]]=true;
		fr[a[lin[i]].y]=fr[s[tot]]+a[lin[i]].c;
		pre[a[lin[i]].y]=i;
	}
	s[++tot]=n;is[s[tot]]=true;
	for(int i=L;i>=1;i--)ba[s[i]]=ba[s[i+1]]+a[lin[i]].c;
	
//	for(int i=1;i<=tot;i++)printf("%d ",s[i]);
//	puts("");
	memset(d,63,sizeof(d));d[1]=0;
	spfa(1);
	for(int i=1;i<=L;i++)
	{
		while(heap.size()&&heap.top().second<i)heap.pop();
		if(!heap.size())puts("-1");
		else pr2(heap.top().first);
		no[i]=false;
		d[s[i+1]]=d[s[i]]+a[lin[i]].c;
		spfa(s[i+1]);
	}
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值