HDU 5361 最短路變形
阿新 • • 發佈:2019-02-08
題意:給了n個點排成一行,每兩個距離為1,然後對於每個點來說它有個L和R,意思是距離在L到R中間的所有點它都能到達,費用是C,問從小出發的單源所有的點的距離
思路:看了網上神犇的題解有了點思路,因為每個點出去的費用都是相同的,而且費用的值大於0,那麼1點直接到達的所有點的最短路就不需要在更新了,因為剩下的肯定是比它大的,那麼對於這些個點我們壓入佇列,但是注意我們這裡的dis設定為點的加和,然後出發的又是最短的,到達的沒有訪問過的點又是最小的,所以不需要最短路時的一個點可以訪問多次更新最小值,然後對於訪問過的點我們可以用並查集來判斷,對於一個點來說,它若訪問過則與右邊的點合併,這樣我們就可以直接訪問下一個沒被訪問過的點,而不需要暴力尋找了,優化的就是這裡
#pragma comment(linker, "/STACK:102400000,102400000") #include <queue> #include <stdio.h> #include <string.h> #include <stdlib.h> #include <iostream> #include <algorithm> #include <functional> using namespace std; typedef long long ll; typedef unsigned long long ull; const int inf=0x3f3f3f3f; const ll INF=0x3f3f3f3f3f3f3f3fll; const int maxn=200010; typedef pair<ll,int> P; int L[maxn],R[maxn],f[maxn],n; ll dis[maxn],C[maxn]; int find1(int x){ if(x!=f[x]) f[x]=find1(f[x]); return f[x]; } void unite(int a,int b){ int aa=find1(a); int bb=find1(b); if(aa==bb) return ; f[aa]=bb; } void dijkstra(int s){ priority_queue<P,vector<P>,greater<P> >que; memset(dis,INF,sizeof(dis)); dis[s]=C[s]; que.push(P(0,s)); while(!que.empty()){ P p=que.top();que.pop(); int v=p.second; for(int i=-1;i<=1;i+=2){ int le=v+i*L[v]; int ri=v+i*R[v]; if(le>ri) swap(le,ri); le=max(1,le); ri=min(ri,n); if(le>ri) continue; int ff=le; while(1){ ff=find1(ff); if(ff>ri) break; if(dis[ff]>dis[v]+C[ff]){ dis[ff]=dis[v]+C[ff]; que.push(P(dis[ff],ff)); } unite(ff,ff+1); ff++; } } } } int main(){ int T; scanf("%d",&T); while(T--){ scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&L[i]); for(int i=1;i<=n;i++) scanf("%d",&R[i]); for(int i=1;i<=n;i++) scanf("%I64d",&C[i]); for(int i=1;i<n+5;i++) f[i]=i; dijkstra(1); for(int i=1;i<=n;i++){ if(dis[i]!=INF){ if(i==n) printf("%I64d\n",dis[i]-C[i]); else printf("%I64d ",dis[i]-C[i]); }else{ if(i==n) printf("-1\n"); else printf("-1 "); } } } return 0; }