[HNOI2014]道路堵塞
题目描述
A国有N座城市,依次标为1到N。同时,在这N座城市间有M条单向道路,每条道路的长度是一个正整数。现在,A国交通部指定了一条从城市1到城市N的路径,并且保证这条路径的长度是所有从城市1到城市N的路径中最短的。不幸的是,因为从城市1到城市N旅行的人越来越多,这条由交通部指定的路径经常发生堵塞。现在A国想知道,这条路径中的任意一条道路无法通行时,由城市1到N的最短路径长度是多少。
输入输出格式
输入格式:
输入文件第一行是三个用空格分开的正整数N、M和L,分别表示城市数目、单向道路数目和交通部指定的最短路径包含多少条道路。按下来M行,每行三个用空格分开的整数a、b和c,表示存在一条由城市a到城市b的长度为c的单向道路。这M行的行号也是对应道路的编号,即其中第1行对应的道路编号为1,第2行对应的道路编号为2,...,第M行对应的道路编号为M。最后一行为L个用空格分开的整数sp(1)...,,sp(L),依次表示从城市1到城市N的由交通部指定的最短路径上的道路的编号。
输出格式:
输出文件包含L行,每行为一个整数,第i行(i=1,2...,,L)的整数表示删去编号为sp(i)的道路后从城市1到城市N的最短路径长度。如果去掉后没有从城市1到城市N的路径,则输出一1。
输入输出样例
4 5 2 1 2 2 1 3 2 3 4 4 3 2 1 2 4 3 1 5
6 6
说明
100%的数据满足2<N<100000,1<M<200000。所用道路长度大于0小于10000。
题解:
玄学大火题,有这样一个结论:
去掉最短路上的一条边后,那么现在的最短路一定是 先沿原最短路走一段->再绕原非最短路走一端->再走回原最短路.
所以我们就可以开始乱搞,从1开始枚举删除最短路上的边,然后用该边的左端点,在断掉该边后,去松弛原最短路上编号大于该点的点,
然后答案就是f[u]+last[u] (last[u]为u到n的最短路) 注意此题f数组不需要清空,然后我们就把f[u]+last[u]加入堆中,然后每一组询问我们先删除不合法的点(u在最短路上的编号小于当前边左端点编号),然后当前的堆顶就是答案,堆为空就是-1
1 #include <algorithm> 2 #include <iostream> 3 #include <cstdlib> 4 #include <cstring> 5 #include <cstdio> 6 #include <cmath> 7 #include <queue> 8 using namespace std; 9 const int N=100005,M=200005; 10 int gi(){ 11 int str=0;char ch=getchar(); 12 while(ch>'9' || ch<'0')ch=getchar(); 13 while(ch>='0' && ch<='9')str=(str<<1)+(str<<3)+ch-48,ch=getchar(); 14 return str; 15 } 16 int n,m,ps,num=0,head[N]; 17 struct Lin{ 18 int next,to,dis,id; 19 }a[M]; 20 void init(int x,int y,int dis,int ids){ 21 a[++num].next=head[x];a[num].to=y;a[num].dis=dis;a[num].id=ids;head[x]=num; 22 } 23 struct edge{ 24 int x,y,dis; 25 }e[M]; 26 struct node{ 27 int id,dist; 28 bool operator <(const node &pp)const{ 29 return dist>pp.dist; 30 } 31 }; 32 priority_queue<node>st; 33 int last[N],imp[M],f[N],q[N*10],mod=N*10,id[N];bool vis[N],mark[N]; 34 void spfa(int k) 35 { 36 memset(vis,0,sizeof(vis)); 37 int t=0,sum=1,x,u;q[1]=e[k].x;vis[e[k].x]=true; 38 while(t!=sum){ 39 t++;if(t==mod)t-=mod;x=q[t]; 40 for(int i=head[x];i;i=a[i].next){ 41 if(a[i].id==k)continue; 42 u=a[i].to; 43 if(f[x]+a[i].dis<f[u]){ 44 f[u]=a[i].dis+f[x]; 45 if(mark[u] && id[u]>id[e[k].x]){ 46 st.push((node){u,f[u]+last[u]}); 47 } 48 if(!vis[u] && !mark[u]){ 49 vis[u]=true; 50 sum++;if(sum==mod)sum-=mod;q[sum]=u; 51 } 52 } 53 } 54 vis[x]=false; 55 } 56 } 57 void work() 58 { 59 n=gi();m=gi();ps=gi(); 60 for(int i=1;i<=m;i++){ 61 e[i].x=gi();e[i].y=gi();e[i].dis=gi(); 62 init(e[i].x,e[i].y,e[i].dis,i); 63 } 64 for(int i=1;i<=ps;i++)imp[i]=gi(),id[e[imp[i]].y]=id[e[imp[i]].x]+1; 65 for(int i=ps;i>=1;i--){ 66 last[e[imp[i]].x]=last[e[imp[i]].y]+e[imp[i]].dis; 67 mark[e[imp[i]].x]=true;mark[e[imp[i]].y]=true; 68 } 69 int x,y; 70 memset(f,127/3,sizeof(f));f[1]=0; 71 for(int i=1;i<=ps;i++){ 72 x=e[i].x;y=e[i].y; 73 if(i>1)f[e[imp[i-1]].y]=f[e[imp[i-1]].x]+e[imp[i-1]].dis; 74 spfa(imp[i]); 75 while(!st.empty() && id[st.top().id]<=id[e[imp[i]].x])st.pop(); 76 if(st.empty())printf("-1\n"); 77 else{ 78 printf("%d\n",st.top().dist); 79 } 80 } 81 } 82 int main() 83 { 84 work(); 85 return 0; 86 }