链接: http://codeforces.com/problemset/problem/230/D
题意: 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;
}