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,分別表示城市數目、單向道路數目和交通部指定的最短路徑包含多少條道路。
Output
輸出文件包含L行,每行為一個整數,第i行(i=1,2…,,L)的整數表示刪去編號為sp(i)的道路後從城市1到城市N的最短路徑長度。如果去掉後沒有從城市1到城市N的路徑,則輸出一1。
Sample Input
4 5 21 2 2
1 3 2
3 4 4
3 2 1
2 4 3
1 5
Sample Output
66
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 道路阻塞