codeforces 230d(最短路+預處理)
阿新 • • 發佈:2018-12-24
題意: n個點 m 條邊 現在你找到從1到n的最短路,但是這裡有一個限制就是如果你在時間t到達節點u 如果有其他人也在這個時間到節點u 那麼你就要等這個人走了之後才能離開u。
思路: 對於每一個點開個vector 存其他人在什麼時間到達,並且預處理出我如果在該時間到,我應該在什麼時間離開。然後就是最短路了。坑點: 如果到節點n 直接記錄最小值就可以了。
程式碼:
#include<bits/stdc++.h> using namespace std; typedef long long ll; const ll inf =1e18+5; typedef pair<ll,ll> pll; const int N = 1e5+5; struct node { int v; ll w; }; vector<node>ve[N]; set<ll >se[N]; vector<pll>ve1[N]; int n,m,k; int vis[N]; ll dis[N]; void dij() { for(int i=0;i<=n;i++){ dis[i]=inf; vis[i]=0; } priority_queue<pll,vector<pll>,greater<pll> >q; int l,r,mid,ans; if(se[1].count(0)){ dis[1]=ve1[1][0].second; q.push(pll(ve1[1][0].second,1)); } else{ dis[1]=0; q.push(pll(0,1)); } int u,v; ll w,dd; ll Ans=inf; while(!q.empty()){ pll tmp=q.top(); q.pop(); u=tmp.second; if(tmp.first>dis[u]) continue; vis[u]=1; for(int i=0;i<ve[u].size();i++){ v=ve[u][i].v; if(vis[v]) continue; w=dis[u]+ve[u][i].w; if(v==n){ Ans=min(Ans,w); } if(se[v].count(w)){ l=0; r=ve1[v].size()-1; while(l<=r){ mid=(l+r)>>1; if(ve1[v][mid].first<=w){ ans=mid; l=mid+1; } else r=mid-1; } dd=ve1[v][ans].second; if(dd<dis[v]){ dis[v]=dd; q.push(pll(dis[v],v)); } } else{ if(w<dis[v]){ dis[v]=w; q.push(pll(dis[v],v)); } } } } if(Ans==inf) printf("-1\n"); else printf("%lld\n",Ans); } int main() { scanf("%d %d",&n,&m); int u,v; ll w; for(int i=1;i<=m;i++){ scanf("%d %d %lld",&u,&v,&w); ve[u].push_back((node){v,w}); ve[v].push_back((node){u,w}); } ll tim; for(int i=1;i<=n;i++){ scanf("%d",&k); while(k--){ scanf("%lld",&tim); ve1[i].push_back(pll(tim,0)); se[i].insert(tim); } } for(int i=1;i<=n;i++){ sort(ve1[i].begin(),ve1[i].end()); for(int j=ve1[i].size()-1;j>=0;j--){ if(j==ve1[i].size()-1){ ve1[i][j].second=ve1[i][j].first+1; } else{ if(ve1[i][j].first==ve1[i][j+1].first-1){ ve1[i][j].second=ve1[i][j+1].second; } else ve1[i][j].second=ve1[i][j].first+1; } } } dij(); return 0; }