【題解】LOJ2759. 「JOI 2014 Final」飛天鼠(最短路)
考慮最終答案的構成,一定是由很多飛行+一些上升+一些下降構成。
由於在任何一個點上升或者下降代價是一樣的,所以:
對於上升操作來說,只要保證前面飛行合法就不需要上升。當且僅當我飛不過去了才上升。
對於下降操作來說,只要我不會越過目標點就不需要下降。當且僅當我會越過目標點才下降。
也就是說,上升和下降操作是不需要手動進行決策的,不存在一種更優解使得這種解通過提前上升或者下降來使得時間花費縮短。因爲假設存在一種“更優解”,可以通過儘量延後上升操作而構造出一組滿足上面兩個原則的同樣優的解。
所以對於每個點,記錄一個\(Height\)表示當前高度和\(dis\)表示花費時間直接Dijkstra即可。
分析一下複雜度,不管如何代價都是正的,所以同樣是\(O(n \log m)\)
在讀入的時候順便刪掉不合法邊...
//@winlere
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
using namespace std; typedef long long ll;
inline int qr(){
register int ret=0,f=0;
register char c=getchar();
while(c<48||c>57)f|=c==45,c=getchar();
while(c>=48&&c<=57) ret=ret*10+c-48,c=getchar();
return f?-ret:ret;
}
const int maxn=1e5+5;
const ll inf=1e18;
typedef pair<ll,int> P;
typedef priority_queue<P,vector<P>,greater<P> > Qp;
Qp q;
ll d[maxn];
int Height[maxn];
pair<int,pair<int,int> > last[maxn];
vector< pair<int,int> > e[maxn];
int h[maxn];
int n,m,X;
inline void add(const int&fr,const int&to,const int&w){
e[fr].push_back({to,w});
}
inline bool dij(){
Qp().swap(q);
for(int t=1;t<=n;++t) d[t]=inf,Height[t]=0;
d[1]=0; Height[1]=X; q.push({0,1});
while(q.size()){
auto now=q.top();
int Cur=now.second,H=Height[Cur];
q.pop();
if(now.first>d[Cur]) continue;
for(auto t:e[Cur]){
int to=t.first;
ll len=t.second;
if(H-len>h[to]){
ll g=H-h[to]+d[Cur];
if(d[to]>g){
d[to]=g;
Height[to]=h[to];
q.push({d[to],to});
}
continue;
}
if(H-len<0){
ll g=d[Cur]+len-H+len;
if(d[to]>g){
d[to]=g;
Height[to]=0;
q.push({d[to],to});
}
continue;
}
if(d[to]>d[Cur]+len){
d[to]=d[Cur]+len;
Height[to]=H-len;
q.push({d[to],to});
continue;
}
}
}
if(d[n]==inf) return 0;
return 1;
}
int main(){
n=qr(); m=qr(); X=qr();
for(int t=1;t<=n;++t) h[t]=qr();
for(int t=1;t<=m;++t){
int t1=qr(),t2=qr(),t3=qr();
if(t3<=h[t1]) add(t1,t2,t3);
if(t3<=h[t2]) add(t2,t1,t3);
}
if(!dij()) return puts("-1"),0;
ll ans=d[n]+h[n]-Height[n];
printf("%lld\n",ans);
return 0;
}