1. 程式人生 > >BZOJ3575 HNOI2014 道路阻塞

BZOJ3575 HNOI2014 道路阻塞

所有 etc else efi stack 我們 operator fff clu

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:嗯?)。

BZOJ3575 HNOI2014 道路阻塞