Problem:
MathJax.Hub.Config({
tex2jax: {inlineMath: [['$','$'], ['\\(','\\)']]}
});

G: 雨降りバス乗り換え

背景

今日は AOR イカちゃんにとって初となるデートの日だ。
AOR イカちゃんは駅からバスを乗り継ぎ、待ち合わせ場所のバス停に向かう予定である。

AOR イカちゃんが駅に着いた時、不幸にも雨が降ってきた。当初予定していた経路ではバスの待ち時間で濡れてしまい、せっかく整えた身だしなみが台無しになってしまう可能性がある。

そこで、バスの待ち時間が最も少なくなるような経路でバス停まで向かうことにした。
AOR イカちゃんは、待ち合わせ場所のバス停に着くまでにどの程度濡れるのか心配している。

問題

AOR イカちゃんは時刻 $0$ に $S$ 番目のバス停におり、そこから $G$ 番目のバス停まで行きたいと考えている。

バス停の個数 $N$ と、異なるバス停同士を繋ぐ $M$ 個の経路 (※) が与えられる。
バス停には、それぞれ $1, \dots, N$ の番号がふられている。

各経路は、出発地 $u$ 、目的地 $v$ 、出発時刻 $t$ 、所要時間 $c$ の $4$ つの値からなる。
時刻 $t$ に出発地 $u$ にいればバスに乗ることができ、時刻 $t + c$ に目的地 $v$ へ到着する。

バスに乗っていない間、 AOR イカちゃんは雨に濡れてしまう。
雨にぬれる時間が最小となる経路を通り $G$ 番目のバス停へ向かう時、時刻 $0$ から $G$ 番目のバス停に着くまでの間に雨に濡れた時間の合計を出力せよ。

(※) グラフ理論の用語における経路とは頂点と辺の列であるが，ここでは辺の意味で使われていることに注意してほしい。

制約

$2 \le N \le 10^5$

$1 \le M \le 2 \times 10^5$

$1 \le S , G \le N$

$1 \le u_i , v_i \le N$

$0 \le t_i \le 10^5$

$1 \le c_i \le 10^5$

$S \neq G$

$u_i \neq v_i$

出発地 $u$ と目的地 $v$ が同じであるような経路は存在しない。

出発地 $u$ と目的地 $v$ を結ぶ経路は複数存在する場合がある。

バスの乗り降り、乗り換えに時間はかからないものとする。

$G$ 番目のバス停へ到着する時間は問わない。

$S$ 番目のバス停から $G$ 番目のバス停へ到着できることは保証されている。

入力

入力は以下の形式で標準入力から与えられる。

$N \ M \ S \ G$

$u_1 \ v_1 \ t_1 \ c_1$

$\vdots$

$u_M \ v_M \ t_M \ c_M$

出力

雨に濡れた最小の時間を 1 行で出力せよ。また、末尾に改行も出力せよ。

サンプル

入力例 1

2 2 1 2
1 2 10 100
1 2 5 500

出力例 1

5

到着時間が遅くても、できるだけ雨に濡れない経路を選ぶ。

入力例 2

3 2 1 3
1 2 0 123
2 3 123 500

出力例 2

0

乗り換えに時間はかからない。

Solution in C (judge verdict: Accepted)

// AOJ 2811 Rainy Bus Stops
// 2018.3.10 bal4u@uu

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#if 1
#define gc() getchar_unlocked()
#else
#define gc() getchar()
#endif
int in()
{
	int n = 0, c = gc();
	do n = 10 * n + (c & 0xf), c = gc(); while (c >= '0');
	return n;
}

// 数値のハッシュ関数
#define HASHSIZ 500009
long long hash[HASHSIZ + 5], *hashend = hash + HASHSIZ;

int insert(int n, int t)
{
	long long x;
	long long *p;
	
	x = ((long long)n << 20) | (t + 1);
	p = hash + (int)(x % HASHSIZ);
	while (*p) {
		if (*p == x) return 0;
		if (++p == hashend) p = hash;
	}
	*p = x;
	return 1;
}

#define MAX 100000
typedef struct { int n, t, w; } QUE;
QUE que[MAX]; int qsize;

#define PARENT(i) ((i)>>1)
#define LEFT(i)   ((i)<<1)
#define RIGHT(i)  (((i)<<1)+1)

void min_heapify(int i)
{
	int l, r, min;
	QUE qt;

	l = LEFT(i), r = RIGHT(i);
	if (l < qsize && que[l].w < que[i].w) min = l; else min = i;
	if (r < qsize && que[r].w < que[min].w) min = r;
	if (min != i) {
		qt = que[i], que[i] = que[min], que[min] = qt;
		min_heapify(min);
	}
}

void deq()
{
	que[0] = que[--qsize];
	min_heapify(0);
}

void enq(int n, int t, int w)
{
	int i, min;
	QUE qt;

	i = qsize++;
	que[i].n = n, que[i].t = t, que[i].w = w;
	while (i > 0 && que[min = PARENT(i)].w > que[i].w) {
		qt = que[i], que[i] = que[min], que[min] = qt;
		i = min;
	}
}

int N, M;
int S, G;
typedef struct { int v, t, c; } T;
T *to[100002]; int hi[100002];

int dijkstra(int start, int goal)
{
	int i, s, t, w;

	qsize = 0;
	enq(start, 0, 0);
	while (qsize) {
		s = que[0].n, t = que[0].t, w = que[0].w; deq();
//printf("s=%d, goal=%d, w=%d\n", s, goal, w);
		if (s == goal) return w;
		if (!insert(s, t)) continue;
		for (i = 0; i < hi[s]; i++) {
			if (t <= to[s][i].t)
				enq(to[s][i].v, to[s][i].c, w + to[s][i].t - t);
		}
	}
	return -1;
}

int main()
{
	int i, k, u, v, t;
	int *memo, sz;

	N = in(), M = in(), S = in() - 1, G = in() - 1;
	memo = malloc(M * 4 * sizeof(int));
	sz = 0;
	for (i = 0; i < M; i++) {
		memo[sz++] = u = in() - 1, memo[sz++] = in() - 1;
		memo[sz++] = in(), memo[sz++] = in();
		hi[u]++;
	}
	for (i = 0; i < N; i++) if (hi[i]) to[i] = malloc(hi[i] * sizeof(T));
	memset(hi, 0, N * sizeof(int));
	i = 0; while (i < sz) {
		u = memo[i++], v = memo[i++];
		k = hi[u]++, to[u][k].v = v;
		to[u][k].t = t = memo[i++];
		to[u][k].c = t + memo[i++];
	}
//	free(memo);

	printf("%d\n", dijkstra(S, G));
	return 0;
}