Codeforces 141 D. Take-off Ramps

問題

長さLのスキーのコースがある。
n個のジャンプ台があり、それぞれの座標はx[i]
ジャンプ台を使うと、x[i]+d[i]に、t[i]の時間をかけて飛ぶことができる。
ただし、ジャンプ台を使うためにはx[i]-p[i]から地上を滑っている必要がある。


スキーヤーが地上をすべるスピードは1であるとき、
コースを滑り終えるのにかかる最短時間を求めよ。


コースは逆走してもよいが、ジャンプはゴール方向へとしか飛べない。
また、コースの外にはみ出てはならない。

制約条件

n≦10^5
L≦10^9

方針

単なるDijkstra+経路復元(+座標圧縮)。
Dijkstraとか久々すぎて存在が頭の中から消えていた。


費用流のときは毎回書いているはずなのに。
経路復元をするので、ノードに、直前のノードの情報を持たせる。
逆走できることを忘れずに。

ソースコード

const int MX=200002;
int v[MX],m,prev[MX],prevjump[MX];
vi jump[MX];

void run()
{
	int n,L; cin>>n>>L;
	vi x(n),d(n),t(n),p(n);
	
	m=0;
	rep(i,n){
		cin>>x[i]>>d[i]>>t[i]>>p[i];
		if(x[i]-p[i]>=0)v[m++]=x[i]-p[i];
		v[m++]=x[i]+d[i];
	}
	v[m++]=0; v[m++]=L;
	
	sort(v,v+m);
	m=unique(v,v+m)-v;
	
	rep(i,n)if(x[i]-p[i]>=0){
		int pos=lower_bound(v,v+m,x[i]-p[i])-v;
		jump[pos].pb(i);
	}
	
	rep(i,m)prev[i]=prevjump[i]=-1;
	
	priority_queue<pair<pi,pi> > q;
	q.push(mp(mp(0,0),mp(-1,-1)));
	while(!q.empty()){
		int c=q.top().first.second, cost=q.top().first.first;
		int prv=q.top().second.first, pj=q.top().second.second;
		q.pop();
		if(prev[c]>=0)continue;
		prev[c]=prv;
		prevjump[c]=pj;
		
		if(c==m-1){
			cout<<-cost<<endl;
			break;
		}
		
		rep(i,jump[c].size()){
			int id=jump[c][i], dist=p[id]+t[id];
			int pos=lower_bound(v,v+m,x[id]+d[id])-v;
			if(prev[pos]<0)q.push(mp(mp(cost-dist,pos),mp(c,id)));
		}
		if(c<m-1)q.push(mp(mp(cost-(v[c+1]-v[c]),c+1),mp(c,-1)));
		if(c&&prev[c-1]<0)q.push(mp(mp(cost-(v[c]-v[c-1]),c-1),mp(c,-1)));
	}
	int i=m-1;
	vi ans;
	while(i!=0){
		if(prevjump[i]>=0)ans.pb(prevjump[i]+1);
		i=prev[i];
	}
	reverse(all(ans));
	cout<<ans.size()<<endl;
	rep(i,ans.size())cout<<ans[i]<<(i==ans.size()-1?"\n":" ")<<endl;
}