BZOJ3575 HNOI2014 道路阻塞

3575: [Hnoi2014]道路堵塞

Time Limit: 10 Sec  Memory Limit: 128 MB

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。

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

100%的数据满足2<N<100000,1<M<200000。所用道路长度大于0小于10000。
数据已加强By Vfleaking

 

  你看见我的跳蚤国王了吗?哦它被FFF了?资磁!

  这题真是火的冒烟,劲爆无比,谁也想不到正解来自一个很扯淡的证明。

  正解:SPFA鬼畜技巧。

  因为它已经钦定了最短路,而且要对最短路上每一条边输出一次答案,所以很容易想到正解是枚举BAN哪条边再鬼一鬼。

  这里有个十分扯淡的证明:新·最短路一腚是S->之前最短路上某一点p->之前最短路上某一点q->T;

  感觉并不知道怎么证明是吧,但如果我说S和p,q和T 可以为同一个点呢?

  那么所有的情况都被包含了是的吗?没错是的。您强×把答案放在了一个鬼证明上。

  所以按照这个证明的思想,我们枚举删掉最短路上的哪条边,然后把这条边的s加进队列做SPFA。

  但是这样不加优化的做法会让你过吗?答案是显然否定的。那么来点更劲的:

  先把最短路上的所有边都BAN掉,然后从S到T开始恢复边,并把s丢进队列。

  然后每次就可以不清空dis数组了,因为你之前SPFA的结果你都可以调用以前的结果。

  然后统计答案就是把走到的钦定最短路上的点的距离加上它到T的距离取个min就好了。这里有一个玄妙的做法就是把答案加上这个点放成结构体扔进堆里,每次弹出到达点在s之前的点因为这是在这条路被BAN的时候SPFA到的,不一定是当前的合法方案,也不会比最优答案更好。所以判完-1后,第一个在s之后的点就不管是不是s更新的点了,却又是一个合法的点,就避免了很多麻烦。

  代码还是很好看懂的。

#include    <iostream>
#include    <cstdio>
#include    <cstdlib>
#include    <algorithm>
#include    <vector>
#include    <cstring>
#include    <queue>
#include    <complex>
#include    <stack>
#define LL long long int
#define dob double
using namespace std;
 
const int N = 200010;
struct Node{int from,to,val,next;}E[N];
struct Data{int p,val;bool operator <(const Data &b)const{return val>b.val;}};
int n,m,L,head[N],tot,ban[N],rk[N],In[N],far[N],dis[N],fr[N],s[N];
queue<int>Q;priority_queue<Data>T;
 
int gi()
{
  int x=0,res=1;char ch=getchar();
  while(ch>'9'||ch<'0'){if(ch=='-')res*=-1;ch=getchar();}
  while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
  return x*res;
}
 
inline void link(int u,int v,int c)
{
  E[++tot]=(Node){u,v,c,head[u]};
  head[u]=tot;
}
 
inline void SPFA(int st)
{
  queue<int>Q;Q.push(st);
  while(!Q.empty()){
    int x=Q.front();Q.pop();In[x]=0;
    for(int e=head[x];e;e=E[e].next){
      if(ban[e])continue;int y=E[e].to;
      if(far[x]+E[e].val<far[y]){
        far[y]=far[x]+E[e].val;
        if(fr[y])T.push((Data){fr[y],far[y]+dis[fr[y]]});
        else if(!In[y])Q.push(In[y]=y);
      }
    }
  }
}
 
int main()
{
  n=gi();m=gi();L=gi();
  for(int i=1;i<=m;++i){
    int u=gi(),v=gi(),c=gi();
    link(u,v,c);
  }
  s[1]=1;fr[1]=1;
  for(int i=1;i<=L;++i){
    ban[rk[i]=gi()]=1;
    s[i+1]=E[rk[i]].to;
    fr[s[i+1]]=i+1;
  }
  for(int i=L;i;--i)
    dis[i]=dis[i+1]+E[rk[i]].val;
  memset(far,127/3,sizeof(far));far[1]=0;
  SPFA(1);
  for(int i=1;i<=L;++i){
    while(!T.empty() && T.top().p<=i)T.pop();
    if(T.empty())printf("-1\n");
    else printf("%d\n",T.top().val);
    far[E[rk[i]].to]=far[s[i]]+E[rk[i]].val;
    SPFA(s[i+1]);
  }
  return 0;
}

  

  这还真TMD妙不可言,玄之又玄,精妙绝伦啊(伦boy:嗯?)。

posted @ 2017-07-21 22:59  Fenghr  阅读(464)  评论(1编辑  收藏  举报