【题解】LOJ2759. 「JOI 2014 Final」飞天鼠(最短路)

【题解】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;
}

posted @ 2019-10-02 14:18 谁是鸽王 阅读(...) 评论(...) 编辑 收藏