open Batteries
module EnumL = Enum.Labels
module ListL = List.Labels
module ArrayL = Array.Labels

let dbg0 x = Printf.eprintf "[debug]%s\n" @@ dump x
let dbg1 x = dbg0 x; x

let id = identity

let (++) n m = List.range n `To m
let (++-) n m = if n >= m then List.range n `Downto m else []
let (++^) n m = if n < m then List.range n `To (pred m) else []

module ModOp = struct
  let prime = 1_000_000_007
  let (-) a b = (a + prime - b) mod prime
  let (+) a b = (a + b) mod prime
  let ( * ) a b = (a * b) mod prime

  let rec pow x n =
    if n = 0 then 1
    else if n mod 2 = 0 then pow (x*x) (n/2)
    else x * pow (x*x) (n/2)
end

let scan fmt = Scanf.sscanf (read_line ()) fmt

let scan_lines n fmt f =
  if n = 0 then []
  else List.map (fun _ -> scan fmt f) (1 ++ n)

let scan_list ?sep cnv =
  let line = read_line () in
  (match sep with
   | None -> List.map String.of_char @@ String.to_list line
   | Some sep -> String.split_on_char sep line)
  |> List.map cnv

let scan_array ?sep cnv = Array.of_list @@ scan_list ?sep cnv

let scan_matrix n m e ?sep conv =
  let arr = Array.make_matrix n m e in
  ListL.iter (0 ++^ n)
    ~f:(fun i -> arr.(i) <- Array.of_list @@ scan_list ?sep conv);
  arr

let atoi c = Char.code c - Char.code '0'

let rec powerset = function
  | [] -> [[]]
  | hd::tl ->
    let pws =  powerset tl in
    pws @ ListL.map pws ~f:(fun pw -> hd::pw)

let permutations l =
  let rec interleave x = function
    | [] -> [[x]]
    | (hd::tl) as l ->
      (x::l) :: (interleave x tl |> ListL.map ~f:(fun l -> hd::l)) in
  let rec aux = function
    | [] -> [[]]
    | a::rest ->
      aux rest |> ListL.map ~f:(interleave a) |> List.concat in
  aux l

let intersection l =
  EnumL.filter ~f:(fun x -> EnumL.exists ~f:((=) x) @@ Enum.clone l)

let zip l m =
  let n = min (List.length l) (List.length m) in
  List.combine (List.take n l) (List.take n m)

let lower_bound n f =
  let rec aux l u =
    if u - l > 1 then
      let m = (l + u) / 2 in
      if f m then aux l m
      else aux m u
    else u in aux (-1) n

let between n x m = n <= x && x < m

let (n,m,s) = scan "%d %d %d" Tuple3.make
let ls = scan_lines m "%d %d %d %d" Tuple4.make
let ms = Array.of_list @@ scan_lines n "%d %d" Tuple2.make

let num = 2500

let () =
  let mat = Array.make n [] in
  ListL.iter ls ~f:(fun (u,v,a,b) ->
      mat.(pred u) <- (pred v, a, b)::mat.(pred u);
      mat.(pred v) <- (pred u, a, b)::mat.(pred v));
  let dp = Array.make_matrix n (succ num) Int.max_num in
  let rec aux h =
    if Heap.size h = 0 then ()
    else
      let (dist, u, s) = Heap.find_min h in
      if dist > dp.(u).(s) then aux @@ Heap.del_min h
      else
        (let (c,d) = ms.(u) in
         let h = Heap.del_min h in
         let h = if s + c <= num && d + dist < dp.(u).(s+c) then
             Heap.add (d+dist, u, s+c) h
           else h in
         aux @@
         ListL.fold_left mat.(u) ~init:h ~f:(fun h (v,a,b) ->
             if s - a >= 0 then
               let newdist = dist + b in
               if newdist < dp.(v).(s-a) then
                 (dp.(v).(s-a) <- newdist;
                  Heap.add (newdist, v, s-a) h)
               else h
             else h))
  in
  dp.(0).(min s 2500) <- 0;
  aux (Heap.empty |> Heap.add (0, 0, min 2500 s));
  (* Array.print ~sep:"\n" (Array.print Int.print) stderr dp; *)
  ListL.iter (1++^n) ~f:(fun i ->
      Printf.printf "%d\n" @@ Array.min dp.(i))


open Batteries
module EnumL = Enum.Labels
module ListL = List.Labels
module ArrayL = Array.Labels

let dbg0 x = Printf.eprintf "[debug]%s\n" @@ dump x
let dbg1 x = dbg0 x; x

let id = identity

let (++) n m = List.range n `To m
let (++-) n m = if n >= m then List.range n `Downto m else []
let (++^) n m = if n < m then List.range n `To (pred m) else []

module ModOp = struct
  let prime = 1_000_000_007
  let (-) a b = (a + prime - b) mod prime
  let (+) a b = (a + b) mod prime
  let ( * ) a b = (a * b) mod prime

  let rec pow x n =
    if n = 0 then 1
    else if n mod 2 = 0 then pow (x*x) (n/2)
    else x * pow (x*x) (n/2)
end

let scan fmt = Scanf.sscanf (read_line ()) fmt

let scan_lines n fmt f =
  if n = 0 then []
  else List.map (fun _ -> scan fmt f) (1 ++ n)

let scan_list ?sep cnv =
  let line = read_line () in
  (match sep with
   | None -> List.map String.of_char @@ String.to_list line
   | Some sep -> String.split_on_char sep line)
  |> List.map cnv

let scan_array ?sep cnv = Array.of_list @@ scan_list ?sep cnv

let scan_matrix n m e ?sep conv =
  let arr = Array.make_matrix n m e in
  ListL.iter (0 ++^ n)
    ~f:(fun i -> arr.(i) <- Array.of_list @@ scan_list ?sep conv);
  arr

let atoi c = Char.code c - Char.code '0'

let rec powerset = function
  | [] -> [[]]
  | hd::tl ->
    let pws =  powerset tl in
    pws @ ListL.map pws ~f:(fun pw -> hd::pw)

let permutations l =
  let rec interleave x = function
    | [] -> [[x]]
    | (hd::tl) as l ->
      (x::l) :: (interleave x tl |> ListL.map ~f:(fun l -> hd::l)) in
  let rec aux = function
    | [] -> [[]]
    | a::rest ->
      aux rest |> ListL.map ~f:(interleave a) |> List.concat in
  aux l

let intersection l =
  EnumL.filter ~f:(fun x -> EnumL.exists ~f:((=) x) @@ Enum.clone l)

let zip l m =
  let n = min (List.length l) (List.length m) in
  List.combine (List.take n l) (List.take n m)

let lower_bound n f =
  let rec aux l u =
    if u - l > 1 then
      let m = (l + u) / 2 in
      if f m then aux l m
      else aux m u
    else u in aux (-1) n

let between n x m = n <= x && x < m

let (n,m,s) = scan "%d %d %d" Tuple3.make
let ls = scan_lines m "%d %d %d %d" Tuple4.make
let ms = Array.of_list @@ scan_lines n "%d %d" Tuple2.make

let num = 2500

let () =
  let mat = Array.make n [] in
  ListL.iter ls ~f:(fun (u,v,a,b) ->
      mat.(pred u) <- (pred v, a, b)::mat.(pred u);
      mat.(pred v) <- (pred u, a, b)::mat.(pred v));
  let dp = Array.make_matrix n (succ num) Int.max_num in
  let rec aux h =
    if Heap.size h = 0 then ()
    else
      let (dist, u, s) = Heap.find_min h in
      if dist > dp.(u).(s) then aux @@ Heap.del_min h
      else
        (let (c,d) = ms.(u) in
         let h = Heap.del_min h in
         let h = if s + c <= num && d + dist < dp.(u).(s+c) then
             Heap.add (d+dist, u, s+c) h
           else h in
         aux @@
         ListL.fold_left mat.(u) ~init:h ~f:(fun h (v,a,b) ->
             if s - a >= 0 then
               let newdist = dist + b in
               if newdist < dp.(v).(s-a) then
                 (dp.(v).(s-a) <- newdist;
                  Heap.add (newdist, v, s-a) h)
               else h
             else h))
  in
  dp.(0).(min s 2500) <- 0;
  aux (Heap.empty |> Heap.add (0, 0, s));
  (* Array.print ~sep:"\n" (Array.print Int.print) stderr dp; *)
  ListL.iter (1++^n) ~f:(fun i ->
      Printf.printf "%d\n" @@ Array.min dp.(i))

Global OOD problem IDs are disjoint from train, validation, and in-distribution test problem IDs.

Score : 500 points

Problem Statement

There are N cities numbered 1 to N, connected by M railroads.

You are now at City 1, with 10^{100} gold coins and S silver coins in your pocket.

The i-th railroad connects City U_i and City V_i bidirectionally, and a one-way trip costs A_i silver coins and takes B_i minutes.
You cannot use gold coins to pay the fare.

There is an exchange counter in each city. At the exchange counter in City i, you can get C_i silver coins for 1 gold coin.
The transaction takes D_i minutes for each gold coin you give.
You can exchange any number of gold coins at each exchange counter.

For each t=2, ..., N, find the minimum time needed to travel from City 1 to City t. You can ignore the time spent waiting for trains.

Constraints

2 \leq N \leq 50

N-1 \leq M \leq 100

0 \leq S \leq 10^9

1 \leq A_i \leq 50

1 \leq B_i,C_i,D_i \leq 10^9

1 \leq U_i < V_i \leq N

There is no pair i, j(i \neq j) such that (U_i,V_i)=(U_j,V_j).

Each city t=2,...,N can be reached from City 1 with some number of railroads.

All values in input are integers.

Input

Input is given from Standard Input in the following format:

N M S
U_1 V_1 A_1 B_1
:
U_M V_M A_M B_M
C_1 D_1
:
C_N D_N

Output

For each t=2, ..., N in this order, print a line containing the minimum time needed to travel from City 1 to City t.

Sample Input 1

3 2 1
1 2 1 2
1 3 2 4
1 11
1 2
2 5

Sample Output 1

2
14

The railway network in this input is shown in the figure below.

In this figure, each city is labeled as follows:

The first line: the ID number i of the city (i for City i)

The second line: C_i / D_i

Similarly, each railroad is labeled as follows:

The first line: the ID number i of the railroad (i for the i-th railroad in input)

The second line: A_i / B_i

You can travel from City 1 to City 2 in 2 minutes, as follows:

Use the 1-st railroad to move from City 1 to City 2 in 2 minutes.

You can travel from City 1 to City 3 in 14 minutes, as follows:

Use the 1-st railroad to move from City 1 to City 2 in 2 minutes.

At the exchange counter in City 2, exchange 3 gold coins for 3 silver coins in 6 minutes.

Use the 1-st railroad to move from City 2 to City 1 in 2 minutes.

Use the 2-nd railroad to move from City 1 to City 3 in 4 minutes.

Sample Input 2

4 4 1
1 2 1 5
1 3 4 4
2 4 2 2
3 4 1 1
3 1
3 1
5 2
6 4

Sample Output 2

5
5
7

The railway network in this input is shown in the figure below:

You can travel from City 1 to City 4 in 7 minutes, as follows:

At the exchange counter in City 1, exchange 2 gold coins for 6 silver coins in 2 minutes.

Use the 2-nd railroad to move from City 1 to City 3 in 4 minutes.

Use the 4-th railroad to move from City 3 to City 4 in 1 minutes.

Sample Input 3

6 5 1
1 2 1 1
1 3 2 1
2 4 5 1
3 5 11 1
1 6 50 1
1 10000
1 3000
1 700
1 100
1 1
100 1

Sample Output 3

1
9003
14606
16510
16576

The railway network in this input is shown in the figure below:

You can travel from City 1 to City 6 in 16576 minutes, as follows:

Use the 1-st railroad to move from City 1 to City 2 in 1 minute.

At the exchange counter in City 2, exchange 3 gold coins for 3 silver coins in 9000 minutes.

Use the 1-st railroad to move from City 2 to City 1 in 1 minute.

Use the 2-nd railroad to move from City 1 to City 3 in 1 minute.

At the exchange counter in City 3, exchange 8 gold coins for 8 silver coins in 5600 minutes.

Use the 2-nd railroad to move from City 3 to City 1 in 1 minute.

Use the 1-st railroad to move from City 1 to City 2 in 1 minute.

Use the 3-rd railroad to move from City 2 to City 4 in 1 minute.

At the exchange counter in City 4, exchange 19 gold coins for 19 silver coins in 1900 minutes.

Use the 3-rd railroad to move from City 4 to City 2 in 1 minute.

Use the 1-st railroad to move from City 2 to City 1 in 1 minute.

Use the 2-nd railroad to move from City 1 to City 3 in 1 minute.

Use the 4-th railroad to move from City 3 to City 5 in 1 minute.

At the exchange counter in City 5, exchange 63 gold coins for 63 silver coins in 63 minutes.

Use the 4-th railroad to move from City 5 to City 3 in 1 minute.

Use the 2-nd railroad to move from City 3 to City 1 in 1 minute.

Use the 5-th railroad to move from City 1 to City 6 in 1 minute.

Sample Input 4

4 6 1000000000
1 2 50 1
1 3 50 5
1 4 50 7
2 3 50 2
2 4 50 4
3 4 50 3
10 2
4 4
5 5
7 7

Sample Output 4

1
3
5

The railway network in this input is shown in the figure below:

Sample Input 5

2 1 0
1 2 1 1
1 1000000000
1 1

Sample Output 5

1000000001

The railway network in this input is shown in the figure below:

You can travel from City 1 to City 2 in 1000000001 minutes, as follows:

At the exchange counter in City 1, exchange 1 gold coin for 1 silver coin in 1000000000 minutes.

Use the 1-st railroad to move from City 1 to City 2 in 1 minute.

Submitted source-code file size, in bytes.

Execution CPU time reported by official Project CodeNet metadata, in milliseconds.

Peak memory usage reported by official Project CodeNet metadata, in kilobytes.


module WeightedDirectedGraph
  (* 辺の重み *)
  (Weight : sig
    type t
    val zero : t
    val compare : t -> t -> int
  end)
  (* 経路長を優先度としたヒープの実装 *)
  (Heap : sig
    type t
    type elt (* 頂点に相当 *)
    type key = Weight.t (* 経路長に相当 *)
    (* ヒープが空ならNoneを，
       そうでなければ経路長が最小となるbindingを返す
       返したbindingはヒープから削除される *)
    val take_min_binding : t -> (key * elt) option
    (* ヒープにbindingを追加する
       既に同じ頂点についてのbindingが追加されていたら，
       経路長の短い方だけを残しても良いし，何も考えずに追加してもよい．
       前者の実装ならダイクストラ法の実装が時間計算量O((V + E) log V)，
       空間計算量O(V)に改善する *)
    val add : t -> key -> elt -> unit
  end)
  (* 頂点を添字，経路長を要素とした配列の実装 *)
  (Array : sig
    type t
    type key = Heap.elt
    type elt = Heap.key
    val get : t -> key -> elt
    val set : t -> key -> elt -> unit
  end)
: sig
  type weight = Array.elt
  type vertex = Array.key

  (* ダイクストラ法で最短経路を求める関数 *)
  val shortest_path :
    (* 空なヒープ *)
    Heap.t ->
    (* 全ての頂点についての経路長が無限大で初期化された配列
       Array.getした時に極端に大きな経路長が返ってくる実装でも良いし，
       Not_foundが投げられる実装でも良い *)
    Array.t ->
    (* 最短経路を求めたいグラフの，ある頂点から伸びる辺に対してのイテレータ *)
    (vertex -> (vertex -> (weight -> weight) (* 辺を通った際のコストを加算する関数 *) -> unit) -> unit) ->
    (* 始点 *)
    vertex ->
    (* 終点を受け取って，始点からの最短距離を返す関数
       始点から辿り着けない場合，無限大を返すかNot_foundを投げる（Arrayの実装依存）
       この関数を覚えておけば，呼び出しごとの途中までの計算結果がシェアされる *)
    (vertex -> weight)
end
= struct
  type weight = Array.elt
  type vertex = Array.key

  let shortest_path q d es s =
    (* 始点への経路長を0にする *)
    Array.set d s Weight.zero;
    (* 既に最短距離が確定した辺へのクエリを高速化するため，
       ヒープの最小要素をメモしておく *)
    let min_binding = ref (Some (Weight.zero, s)) in
    let rec dijkstra t =
      match !min_binding with
      (* もう既に全ての頂点までの距離が分かっている *)
      | None -> Array.get d t
      | Some (w, u) ->
          match Array.get d t with
          (* 既に終点までの距離が分かっているので返す *)
          | x when 0 <= Weight.compare w x -> x
          (* 終点までの距離が分かっていないので，ダイクストラ法を続行 *)
          | _ ->
              (* 未だ頂点uを訪れていない *)
              if 0 <= Weight.compare (Array.get d u) w then
                es u (fun v f ->
                  (* uからvに伸びる辺を通った際の経路長 *)
                  let c = f w in
                  if 0 < Weight.compare (Array.get d v) c then
                    (Heap.add q c v; Array.set d v c));
              min_binding := Heap.take_min_binding q;
              dijkstra t in
    dijkstra
end

module Int = struct
  type t = int
  let zero = 0
  let compare = compare
end

module IntMap = Map.Make (Int)

module G = WeightedDirectedGraph (Int)
  (struct
    type t = int array list IntMap.t ref
    type key = int
    type elt = int array
    let take_min_binding q =
      match IntMap.min_binding !q with
      | exception Not_found -> None
      | (w, [v]) -> q := IntMap.remove w !q; Some (w, v)
      | (w, v :: vs) -> q := IntMap.add w vs !q; Some (w, v)
    let add q w v  =
      q := IntMap.update w (fun vs -> Some (v :: Option.value ~default:[] vs)) !q
  end)
  (struct
    type t = (int, Bigarray.int_elt, Bigarray.c_layout) Bigarray.Genarray.t
    type elt = int
    type key = int array
    let get = Bigarray.Genarray.get
    let set = Bigarray.Genarray.set
  end)

let () = Scanf.scanf "%d %d %d\n" @@ fun n m s ->
  let es = Array.make n [] in
  for i = 0 to m - 1 do
    Scanf.scanf "%d %d %d %d\n" @@ fun u v a b ->
      es.(u - 1) <- (v - 1, a, b) :: es.(u - 1);
      es.(v - 1) <- (u - 1, a, b) :: es.(v - 1);
  done;
  let vs = Array.init n @@ fun _ -> Scanf.scanf "%d %d\n" @@ fun c d -> (c, d) in
  let d =
    G.shortest_path (ref IntMap.empty)
      (let d = Bigarray.Genarray.create Bigarray.int Bigarray.c_layout [| n; 2501 |] in Bigarray.Genarray.fill d max_int; d)
      (fun [| v; w |] f ->
        List.iter (fun (u, a, b) ->
          if a <= w then
            f [| u; w - a |] (( + ) b)) es.(v);
        let (c, d) = vs.(v) in
        f [| v; min 2500 (w + c) |] (( + ) d))
      [| 0; min 2500 s |] in
  for v = 1 to n - 1 do
    Printf.printf "%d\n" @@
    Array.fold_left min max_int @@
    Array.init 2501 @@ fun w -> d [| v; w |]
  done


module WeightedDirectedGraph
  (* 辺の重み *)
  (Weight : sig
    type t
    val zero : t
    val compare : t -> t -> int
  end)
  (* 経路長を優先度としたヒープの実装 *)
  (Heap : sig
    type t
    type elt (* 頂点に相当 *)
    type key = Weight.t (* 経路長に相当 *)
    (* ヒープが空ならNoneを，
       そうでなければ経路長が最小となるbindingを一つ以上返す
       返したbindingは全てヒープから削除される *)
    val take_min_bindings : t -> (key * elt list) option
    (* ヒープにbindingを追加する
       既に同じ頂点についてのbindingが追加されていたら，
       経路長の短い方だけを残しても良いし，何も考えずに追加してもよい．
       前者の実装ならダイクストラ法の実装が時間計算量O((V + E) log V)，
       空間計算量O(V)に改善する *)
    val add : t -> key -> elt -> unit
  end)
  (* 頂点を添字，経路長を要素とした配列の実装 *)
  (Array : sig
    type t
    type key = Heap.elt
    type elt = Heap.key
    val get : t -> key -> elt
    val set : t -> key -> elt -> unit
  end)
: sig
  type weight = Array.elt
  type vertex = Array.key

  (* ダイクストラ法で最短経路を求める関数 *)
  val shortest_path :
    (* 空なヒープ *)
    Heap.t ->
    (* 全ての頂点についての経路長が無限大で初期化された配列
       Array.getした時に極端に大きな経路長が返ってくる実装でも良いし，
       Not_foundが投げられる実装でも良い *)
    Array.t ->
    (* 最短経路を求めたいグラフの，ある頂点から伸びる辺に対してのイテレータ *)
    (vertex -> (vertex -> (weight -> weight) (* 辺を通った際のコストを加算する関数 *) -> unit) -> unit) ->
    (* 始点 *)
    vertex ->
    (* 終点を受け取って，始点からの最短距離を返す関数
       始点から辿り着けない場合，無限大を返すかNot_foundを投げる（Arrayの実装依存）
       この関数を覚えておけば，呼び出しごとの途中までの計算結果がシェアされる *)
    (vertex -> weight)
end
= struct
  type weight = Array.elt
  type vertex = Array.key

  let shortest_path q d es s =
    (* 始点への経路長を0にする *)
    Array.set d s Weight.zero;
    (* 既に最短距離が確定した辺へのクエリを高速化するため，
       ヒープの最小要素をメモしておく *)
    let min_bindings = ref (Some (Weight.zero, [s])) in
    let rec dijkstra t =
      match !min_bindings with
      (* もう既に全ての頂点までの距離が分かっている *)
      | None -> Array.get d t
      | Some (w, us) ->
          match Array.get d t with
          (* 既に終点までの距離が分かっているので返す *)
          | x when 0 <= Weight.compare w x -> x
          (* 終点までの距離が分かっていないので，ダイクストラ法を続行 *)
          | _ | exception Not_found ->
              List.iter (fun u ->
                (* 未だ頂点uを訪れていない *)
                if 0 <= Weight.compare (Array.get d u) w then
                  es u @@ fun v f ->
                    (* uからvに伸びる辺を通った際の経路長 *)
                    let c = f w in
                    if 0 < Weight.compare (Array.get d v) c then
                      (Heap.add q c v; Array.set d v c)) us;
              min_bindings := Heap.take_min_bindings q;
              dijkstra t in
    dijkstra
end

module PrioritySearchQueue = struct
module type OrderedType = sig
  type t
  val compare : t -> t -> int
end

module Make (Key : OrderedType) (Priority : OrderedType)
: sig
  type key = Key.t
  type priority = Priority.t

  type t
  val is_empty : t -> bool
  val cardinal : t -> int
  val find_opt : key -> t -> priority option
  val mem : key -> t -> bool
  val min_binding_opt : t -> (key * priority) option
  val empty : t
  val singleton : key -> priority -> t
  val add : key -> priority -> t -> t
  val update : key -> (priority option -> priority option) -> t -> t
  val remove : key -> t -> t
  val remove_min_binding : t -> t
  val of_list : (key * priority) list -> t
  val fold : (key -> priority -> 'a -> 'a) -> t -> 'a -> 'a
  val bindings : t -> (key * priority) list
end = struct
  type key = Key.t
  type priority = Priority.t

  type loser_tree =
    | Start
    | LLoser of int * Key.t * Priority.t * loser_tree * Key.t * loser_tree
    | RLoser of int * Key.t * Priority.t * loser_tree * Key.t * loser_tree

  type t =
    | Void
    | Winner of Key.t * Priority.t * loser_tree * Key.t

  let is_empty = function
    | Void -> true
    | Winner (_, _, _, _) -> false

  let cardinal' = function
    | Start -> 0
    | LLoser (s, _, _, _, _, _)
    | RLoser (s, _, _, _, _, _) -> s

  let cardinal = function
    | Void -> 0
    | Winner (_, _, t, _) -> cardinal' t

  let omega = 4

  let left = function
    | Start -> raise (Invalid_argument "left")
    | LLoser (_, _, _, l, _, _)
    | RLoser (_, _, _, l, _, _) -> l

  let right = function
    | Start -> raise (Invalid_argument "right")
    | LLoser (_, _, _, _, _, r)
    | RLoser (_, _, _, _, _, r) -> r

  let max_key = function
    | Void -> raise (Invalid_argument "max_key")
    | Winner (_, _, _, m) -> m

  let lloser k p l m r = LLoser (1 + cardinal' l + cardinal' r, k, p, l, m, r)
  let rloser k p l m r = RLoser (1 + cardinal' l + cardinal' r, k, p, l, m, r)

  let lsingle_left k1 p1 t1 m1 = function
    | Start -> raise (Invalid_argument "lsingle_left")
    | LLoser (_, k2, p2, t2, m2, t3) ->
        if 0 <= Priority.compare p2 p1
        then lloser k1 p1 (rloser k2 p2 t1 m1 t2) m2 t3
        else lloser k2 p2 (lloser k1 p1 t1 m1 t2) m2 t3
    | RLoser (_, k2, p2, t2, m2, t3) ->
        rloser k2 p2 (lloser k1 p1 t1 m1 t2) m2 t3

  let rsingle_left k1 p1 t1 m1 = function
    | Start -> raise (Invalid_argument "rsingle_left")
    | LLoser (_, k2, p2, t2, m2, t3) ->
        rloser k1 p1 (rloser k2 p2 t1 m1 t2) m2 t3
    | RLoser (_, k2, p2, t2, m2, t3) ->
        rloser k2 p2 (rloser k1 p1 t1 m1 t2) m2 t3

  let lsingle_right k1 p1 t1 m2 t3 =
    match t1 with
    | Start -> raise (Invalid_argument "lsingle_right")
    | LLoser (_, k2, p2, t1, m1, t2) ->
        lloser k2 p2 t1 m1 (lloser k1 p1 t2 m2 t3)
    | RLoser (_, k2, p2, t1, m1, t2) ->
        lloser k1 p1 t1 m1 (lloser k2 p2 t2 m2 t3)

  let rsingle_right k1 p1 t1 m2 t3 =
    match t1 with
    | Start -> raise (Invalid_argument "rsingle_right")
    | LLoser (_, k2, p2, t1, m1, t2) ->
        lloser k2 p2 t1 m1 (rloser k1 p1 t2 m2 t3)
    | RLoser (_, k2, p2, t1, m1, t2) ->
        if 0 <= Priority.compare p2 p1
        then rloser k1 p1 t1 m1 (lloser k2 p2 t2 m2 t3)
        else rloser k2 p2 t1 m1 (rloser k1 p1 t2 m2 t3)

  let ldouble_left k1 p1 t1 m1 = function
    | Start -> raise (Invalid_argument "ldouble_left")
    | LLoser (_, k2, p2, t2, m2, t3) ->
        lsingle_left k1 p1 t1 m1 (lsingle_right k2 p2 t2 m2 t3)
    | RLoser (_, k2, p2, t2, m2, t3) ->
        lsingle_left k1 p1 t1 m1 (rsingle_right k2 p2 t2 m2 t3)

  let ldouble_right k1 p1 t1 m2 t3 =
    match t1 with
    | Start -> raise (Invalid_argument "ldouble_right")
    | LLoser (_, k2, p2, t1, m1, t2) ->
        lsingle_right k1 p1 (lsingle_left k2 p2 t1 m1 t2) m2 t3
    | RLoser (_, k2, p2, t1, m1, t2) ->
        lsingle_right k1 p1 (rsingle_left k2 p2 t1 m1 t2) m2 t3

  let rdouble_left k1 p1 t1 m1 = function
    | Start -> raise (Invalid_argument "rdouble_left")
    | LLoser (_, k2, p2, t2, m2, t3) ->
        rsingle_left k1 p1 t1 m1 (lsingle_right k2 p2 t2 m2 t3)
    | RLoser (_, k2, p2, t2, m2, t3) ->
        rsingle_left k1 p1 t1 m1 (rsingle_right k2 p2 t2 m2 t3)

  let rdouble_right k1 p1 t1 m2 t3 =
    match t1 with
    | Start -> raise (Invalid_argument "rdouble_right")
    | LLoser (_, k2, p2, t1, m1, t2) ->
        rsingle_right k1 p1 (lsingle_left k2 p2 t1 m1 t2) m2 t3
    | RLoser (_, k2, p2, t1, m1, t2) ->
        rsingle_right k1 p1 (rsingle_left k2 p2 t1 m1 t2) m2 t3

  let lbalance_left k p l m r =
    if cardinal' (left r) < cardinal' (right r)
    then lsingle_left k p l m r
    else ldouble_left k p l m r

  let lbalance_right k p l m r =
    if cardinal' (left l) > cardinal' (right l)
    then lsingle_right k p l m r
    else ldouble_right k p l m r

  let rbalance_left k p l m r =
    if cardinal' (left r) < cardinal' (right r)
    then rsingle_left k p l m r
    else rdouble_left k p l m r

  let rbalance_right k p l m r =
    if cardinal' (left l) > cardinal' (right l)
    then rsingle_right k p l m r
    else rdouble_right k p l m r

  let lbalance k p l m r =
    if cardinal' l + cardinal' r < 2
    then lloser k p l m r
    else if cardinal' r > omega * cardinal' l
    then lbalance_left k p l m r
    else if cardinal' l > omega * cardinal' r
    then lbalance_right k p l m r
    else lloser k p l m r

  let rbalance k p l m r =
    if cardinal' l + cardinal' r < 2
    then rloser k p l m r
    else if cardinal' r > omega * cardinal' l
    then rbalance_left k p l m r
    else if cardinal' l > omega * cardinal' r
    then rbalance_right k p l m r
    else rloser k p l m r

  let rec play t t' =
    match t, t' with
    | Void, _ -> t'
    | _, Void -> t
    | Winner (k, p, t, m), Winner (k', p', t', m') ->
        if 0 <= Priority.compare p' p
        then Winner (k, p, rbalance k' p' t m t', m')
        else Winner (k', p', lbalance k p t m t', m')

  let find_opt k =
    let rec find_opt_aux k' p' = function
      | Start ->
          if Key.compare k k' = 0
          then Some p'
          else None
      | RLoser (_, k'', p'', l, m, r) ->
          if 0 <= Key.compare m k
          then find_opt_aux k' p' l
          else find_opt_aux k'' p'' r
      | LLoser (_, k'', p'', l, m, r) ->
          if 0 <= Key.compare m k
          then find_opt_aux k'' p'' l
          else find_opt_aux k' p' r in
    function
      | Void -> None
      | Winner (k', p', t, _) -> find_opt_aux k' p' t

  let mem k t = Option.is_some @@ find_opt k t

  let min_binding_opt = function
    | Void -> None
    | Winner (k, p, _, _) -> Some (k, p)

  let empty = Void

  let singleton k p = Winner (k, p, Start, k)

  let add k p =
    let rec add_aux k' p' m' = function
      | Start ->
          let cmp = Key.compare k k' in
          if cmp < 0
          then play (singleton k p) (singleton k' p')
          else if cmp = 0
          then singleton k p
          else play (singleton k' p') (singleton k p)
      | RLoser (_, k'', p'', l, m, r) ->
          if 0 <= Key.compare m k
          then play (add_aux k' p' m l) (Winner (k'', p'', r, m'))
          else play (Winner (k', p', l, m)) (add_aux k'' p'' m' r)
      | LLoser (_, k'', p'', l, m, r) ->
          if 0 <= Key.compare m k
          then play (add_aux k'' p'' m l) (Winner (k', p', r, m'))
          else play (Winner (k'', p'', l, m)) (add_aux k' p' m' r) in
    function
      | Void -> singleton k p
      | Winner (k', p', t, m) -> add_aux k' p' m t

  let update k f =
    let exception Not_modified in
    let rec update_aux k' p' m' = function
      | Start ->
          let cmp = Key.compare k k' in
          if cmp < 0
          then
            begin match f None with
            | None -> raise Not_modified
            | Some p -> play (singleton k p) (singleton k' p')
            end
          else if cmp = 0
          then
            begin match f (Some p') with
            | None -> empty
            | Some p -> if p == p' then raise Not_modified else singleton k p
            end
          else
            begin match f None with
            | None -> raise Not_modified
            | Some p -> play (singleton k' p') (singleton k p)
            end
      | RLoser (_, k'', p'', l, m, r) ->
          if 0 <= Key.compare m k
          then play (update_aux k' p' m l) (Winner (k'', p'', r, m'))
          else play (Winner (k', p', l, m)) (update_aux k'' p'' m' r)
      | LLoser (_, k'', p'', l, m, r) ->
          if 0 <= Key.compare m k
          then play (update_aux k'' p'' m l) (Winner (k', p', r, m'))
          else play (Winner (k'', p'', l, m)) (update_aux k' p' m' r) in
    function
      | Void as t0 ->
          begin match f None with
          | None -> t0
          | Some p -> singleton k p
          end
      | (Winner (k', p', t, m')) as t0 ->
          try update_aux k' p' m' t with Not_modified -> t0

  let remove k =
    let exception Not_modified in
    let rec remove_aux k' p' m' = function
      | Start ->
          if Key.compare k k' = 0
          then empty
          else raise Not_modified
      | RLoser (_, k'', p'', l, m, r) ->
          if 0 <= Key.compare m k
          then play (remove_aux k' p' m l) (Winner (k'', p'', r, m'))
          else play (Winner (k', p', l, m)) (remove_aux k'' p'' m' r)
      | LLoser (_, k'', p'', l, m, r) ->
          if 0 <= Key.compare m k
          then play (remove_aux k'' p'' m l) (Winner (k', p', r, m'))
          else play (Winner (k'', p'', l, m)) (remove_aux k' p' m' r) in
    function
      | Void as t0 -> t0
      | (Winner (k', p', t, m')) as t0 ->
          try remove_aux k' p' m' t with Not_modified -> t0

  let rec second_best m' = function
    | Start -> Void
    | LLoser (_, k, p, l, m, r) -> play (Winner (k, p, l, m)) (second_best m' r)
    | RLoser (_, k, p, l, m, r) -> play (second_best m l) (Winner (k, p, r, m'))

  let remove_min_binding = function
    | Void as t -> t
    | Winner (_, _, t, m) -> second_best m t

  let of_list = List.fold_left (fun t (k, p) -> add k p t) empty

  let fold f =
    let rec fold_aux k p acc = function
      | Start -> f k p acc
      | RLoser (_, k', p', l, _, r) ->
          fold_aux k p (fold_aux k' p' acc r) l
      | LLoser (_, k', p', l, _, r) ->
          fold_aux k' p' (fold_aux k p acc r) l in
    fun t acc ->
      match t with
      | Void -> acc
      | Winner (k, p, t, _) -> fold_aux k p acc t

  let bindings t = fold (fun k p -> List.cons (k, p)) t []
end

end

module Int = struct
  type t = int
  let zero = 0
  let compare = compare
end

module PSQ = PrioritySearchQueue.Make (struct
  type t = int array
  let compare = compare
end) (Int)

module G = WeightedDirectedGraph (Int)
  (struct
    type t = PSQ.t ref
    type elt = int array
    type key = int
    let take_min_bindings q =
      match PSQ.min_binding_opt !q with
      | None -> None
      | Some (v, w) -> q := PSQ.remove_min_binding !q; Some (w, [v])
    let add q w v = q := PSQ.add v w !q
  end)
  (struct
    type t = (int, Bigarray.int_elt, Bigarray.c_layout) Bigarray.Genarray.t
    type elt = int
    type key = int array
    let get = Bigarray.Genarray.get
    let set = Bigarray.Genarray.set
  end)

let () = Scanf.scanf "%d %d %d\n" @@ fun n m s ->
  let es = Array.make n [] in
  for i = 0 to m - 1 do
    Scanf.scanf "%d %d %d %d\n" @@ fun u v a b ->
      es.(u - 1) <- (v - 1, a, b) :: es.(u - 1);
      es.(v - 1) <- (u - 1, a, b) :: es.(v - 1);
  done;
  let vs = Array.init n @@ fun _ -> Scanf.scanf "%d %d\n" @@ fun c d -> (c, d) in
  let d =
    G.shortest_path (ref PSQ.empty)
      (let d = Bigarray.Genarray.create Bigarray.int Bigarray.c_layout [| n; 2501 |] in Bigarray.Genarray.fill d max_int; d)
      (fun [| v; w |] f ->
        List.iter (fun (u, a, b) ->
          if a <= w then
            f [| u; w - a |] (( + ) b)) es.(v);
        let (c, d) = vs.(v) in
        f [| v; min 2500 (w + c) |] (( + ) d))
      [| 0; min 2500 s |] in
  for v = 1 to n - 1 do
    Printf.printf "%d\n" @@
    Array.fold_left min max_int @@
    Array.init 2501 @@ fun w -> d [| v; w |]
  done


module PrioritySearchQueue = struct

  module type OrderedType = sig
    type t
    val compare : t -> t -> int
  end

  module Make (Key : OrderedType) (Priority : OrderedType)
  : sig
    type key = Key.t
    type priority = Priority.t

    type t
    val is_empty : t -> bool
    val cardinal : t -> int
    val find_opt : key -> t -> priority option
    val mem : key -> t -> bool
    val min_binding_opt : t -> (key * priority) option
    val empty : t
    val singleton : key -> priority -> t
    val add : key -> priority -> t -> t
    val update : key -> (priority option -> priority option) -> t -> t
    val remove : key -> t -> t
    val remove_min_binding : t -> t
    val of_list : (key * priority) list -> t
    val fold : (key -> priority -> 'a -> 'a) -> t -> 'a -> 'a
    val bindings : t -> (key * priority) list
  end = struct
    type key = Key.t
    type priority = Priority.t

    type loser_tree =
      | Start
      | LLoser of int * Key.t * Priority.t * loser_tree * Key.t * loser_tree
      | RLoser of int * Key.t * Priority.t * loser_tree * Key.t * loser_tree

    type t =
      | Void
      | Winner of Key.t * Priority.t * loser_tree * Key.t

    let is_empty = function
      | Void -> true
      | Winner (_, _, _, _) -> false

    let cardinal' = function
      | Start -> 0
      | LLoser (s, _, _, _, _, _)
      | RLoser (s, _, _, _, _, _) -> s

    let cardinal = function
      | Void -> 0
      | Winner (_, _, t, _) -> cardinal' t

    let omega = 4

    let left = function
      | Start -> raise (Invalid_argument "left")
      | LLoser (_, _, _, l, _, _)
      | RLoser (_, _, _, l, _, _) -> l

    let right = function
      | Start -> raise (Invalid_argument "right")
      | LLoser (_, _, _, _, _, r)
      | RLoser (_, _, _, _, _, r) -> r

    let max_key = function
      | Void -> raise (Invalid_argument "max_key")
      | Winner (_, _, _, m) -> m

    let lloser k p l m r = LLoser (1 + cardinal' l + cardinal' r, k, p, l, m, r)
    let rloser k p l m r = RLoser (1 + cardinal' l + cardinal' r, k, p, l, m, r)

    let lsingle_left k1 p1 t1 m1 = function
      | Start -> raise (Invalid_argument "lsingle_left")
      | LLoser (_, k2, p2, t2, m2, t3) ->
          if 0 <= Priority.compare p2 p1
          then lloser k1 p1 (rloser k2 p2 t1 m1 t2) m2 t3
          else lloser k2 p2 (lloser k1 p1 t1 m1 t2) m2 t3
      | RLoser (_, k2, p2, t2, m2, t3) ->
          rloser k2 p2 (lloser k1 p1 t1 m1 t2) m2 t3

    let rsingle_left k1 p1 t1 m1 = function
      | Start -> raise (Invalid_argument "rsingle_left")
      | LLoser (_, k2, p2, t2, m2, t3) ->
          rloser k1 p1 (rloser k2 p2 t1 m1 t2) m2 t3
      | RLoser (_, k2, p2, t2, m2, t3) ->
          rloser k2 p2 (rloser k1 p1 t1 m1 t2) m2 t3

    let lsingle_right k1 p1 t1 m2 t3 =
      match t1 with
      | Start -> raise (Invalid_argument "lsingle_right")
      | LLoser (_, k2, p2, t1, m1, t2) ->
          lloser k2 p2 t1 m1 (lloser k1 p1 t2 m2 t3)
      | RLoser (_, k2, p2, t1, m1, t2) ->
          lloser k1 p1 t1 m1 (lloser k2 p2 t2 m2 t3)

    let rsingle_right k1 p1 t1 m2 t3 =
      match t1 with
      | Start -> raise (Invalid_argument "rsingle_right")
      | LLoser (_, k2, p2, t1, m1, t2) ->
          lloser k2 p2 t1 m1 (rloser k1 p1 t2 m2 t3)
      | RLoser (_, k2, p2, t1, m1, t2) ->
          if 0 <= Priority.compare p2 p1
          then rloser k1 p1 t1 m1 (lloser k2 p2 t2 m2 t3)
          else rloser k2 p2 t1 m1 (rloser k1 p1 t2 m2 t3)

    let ldouble_left k1 p1 t1 m1 = function
      | Start -> raise (Invalid_argument "ldouble_left")
      | LLoser (_, k2, p2, t2, m2, t3) ->
          lsingle_left k1 p1 t1 m1 (lsingle_right k2 p2 t2 m2 t3)
      | RLoser (_, k2, p2, t2, m2, t3) ->
          lsingle_left k1 p1 t1 m1 (rsingle_right k2 p2 t2 m2 t3)

    let ldouble_right k1 p1 t1 m2 t3 =
      match t1 with
      | Start -> raise (Invalid_argument "ldouble_right")
      | LLoser (_, k2, p2, t1, m1, t2) ->
          lsingle_right k1 p1 (lsingle_left k2 p2 t1 m1 t2) m2 t3
      | RLoser (_, k2, p2, t1, m1, t2) ->
          lsingle_right k1 p1 (rsingle_left k2 p2 t1 m1 t2) m2 t3

    let rdouble_left k1 p1 t1 m1 = function
      | Start -> raise (Invalid_argument "rdouble_left")
      | LLoser (_, k2, p2, t2, m2, t3) ->
          rsingle_left k1 p1 t1 m1 (lsingle_right k2 p2 t2 m2 t3)
      | RLoser (_, k2, p2, t2, m2, t3) ->
          rsingle_left k1 p1 t1 m1 (rsingle_right k2 p2 t2 m2 t3)

    let rdouble_right k1 p1 t1 m2 t3 =
      match t1 with
      | Start -> raise (Invalid_argument "rdouble_right")
      | LLoser (_, k2, p2, t1, m1, t2) ->
          rsingle_right k1 p1 (lsingle_left k2 p2 t1 m1 t2) m2 t3
      | RLoser (_, k2, p2, t1, m1, t2) ->
          rsingle_right k1 p1 (rsingle_left k2 p2 t1 m1 t2) m2 t3

    let lbalance_left k p l m r =
      if cardinal' (left r) < cardinal' (right r)
      then lsingle_left k p l m r
      else ldouble_left k p l m r

    let lbalance_right k p l m r =
      if cardinal' (left l) > cardinal' (right l)
      then lsingle_right k p l m r
      else ldouble_right k p l m r

    let rbalance_left k p l m r =
      if cardinal' (left r) < cardinal' (right r)
      then rsingle_left k p l m r
      else rdouble_left k p l m r

    let rbalance_right k p l m r =
      if cardinal' (left l) > cardinal' (right l)
      then rsingle_right k p l m r
      else rdouble_right k p l m r

    let lbalance k p l m r =
      if cardinal' l + cardinal' r < 2
      then lloser k p l m r
      else if cardinal' r > omega * cardinal' l
      then lbalance_left k p l m r
      else if cardinal' l > omega * cardinal' r
      then lbalance_right k p l m r
      else lloser k p l m r

    let rbalance k p l m r =
      if cardinal' l + cardinal' r < 2
      then rloser k p l m r
      else if cardinal' r > omega * cardinal' l
      then rbalance_left k p l m r
      else if cardinal' l > omega * cardinal' r
      then rbalance_right k p l m r
      else rloser k p l m r

    let rec play t t' =
      match t, t' with
      | Void, _ -> t'
      | _, Void -> t
      | Winner (k, p, t, m), Winner (k', p', t', m') ->
          if 0 <= Priority.compare p' p
          then Winner (k, p, rbalance k' p' t m t', m')
          else Winner (k', p', lbalance k p t m t', m')

    let find_opt k =
      let rec find_opt_aux k' p' = function
        | Start ->
            if Key.compare k k' = 0
            then Some p'
            else None
        | RLoser (_, k'', p'', l, m, r) ->
            if 0 <= Key.compare m k
            then find_opt_aux k' p' l
            else find_opt_aux k'' p'' r
        | LLoser (_, k'', p'', l, m, r) ->
            if 0 <= Key.compare m k
            then find_opt_aux k'' p'' l
            else find_opt_aux k' p' r in
      function
        | Void -> None
        | Winner (k', p', t, _) -> find_opt_aux k' p' t

    let mem k t = Option.is_some @@ find_opt k t

    let min_binding_opt = function
      | Void -> None
      | Winner (k, p, _, _) -> Some (k, p)

    let empty = Void

    let singleton k p = Winner (k, p, Start, k)

    let add k p =
      let rec add_aux k' p' m' = function
        | Start ->
            let cmp = Key.compare k k' in
            if cmp < 0
            then play (singleton k p) (singleton k' p')
            else if cmp = 0
            then singleton k p
            else play (singleton k' p') (singleton k p)
        | RLoser (_, k'', p'', l, m, r) ->
            if 0 <= Key.compare m k
            then play (add_aux k' p' m l) (Winner (k'', p'', r, m'))
            else play (Winner (k', p', l, m)) (add_aux k'' p'' m' r)
        | LLoser (_, k'', p'', l, m, r) ->
            if 0 <= Key.compare m k
            then play (add_aux k'' p'' m l) (Winner (k', p', r, m'))
            else play (Winner (k'', p'', l, m)) (add_aux k' p' m' r) in
      function
        | Void -> singleton k p
        | Winner (k', p', t, m) -> add_aux k' p' m t

    let update k f =
      let exception Not_modified in
      let rec update_aux k' p' m' = function
        | Start ->
            let cmp = Key.compare k k' in
            if cmp < 0
            then
              begin match f None with
              | None -> raise Not_modified
              | Some p -> play (singleton k p) (singleton k' p')
              end
            else if cmp = 0
            then
              begin match f (Some p') with
              | None -> empty
              | Some p -> if p == p' then raise Not_modified else singleton k p
              end
            else
              begin match f None with
              | None -> raise Not_modified
              | Some p -> play (singleton k' p') (singleton k p)
              end
        | RLoser (_, k'', p'', l, m, r) ->
            if 0 <= Key.compare m k
            then play (update_aux k' p' m l) (Winner (k'', p'', r, m'))
            else play (Winner (k', p', l, m)) (update_aux k'' p'' m' r)
        | LLoser (_, k'', p'', l, m, r) ->
            if 0 <= Key.compare m k
            then play (update_aux k'' p'' m l) (Winner (k', p', r, m'))
            else play (Winner (k'', p'', l, m)) (update_aux k' p' m' r) in
      function
        | Void as t0 ->
            begin match f None with
            | None -> t0
            | Some p -> singleton k p
            end
        | (Winner (k', p', t, m')) as t0 ->
            try update_aux k' p' m' t with Not_modified -> t0

    let remove k =
      let exception Not_modified in
      let rec remove_aux k' p' m' = function
        | Start ->
            if Key.compare k k' = 0
            then empty
            else raise Not_modified
        | RLoser (_, k'', p'', l, m, r) ->
            if 0 <= Key.compare m k
            then play (remove_aux k' p' m l) (Winner (k'', p'', r, m'))
            else play (Winner (k', p', l, m)) (remove_aux k'' p'' m' r)
        | LLoser (_, k'', p'', l, m, r) ->
            if 0 <= Key.compare m k
            then play (remove_aux k'' p'' m l) (Winner (k', p', r, m'))
            else play (Winner (k'', p'', l, m)) (remove_aux k' p' m' r) in
      function
        | Void as t0 -> t0
        | (Winner (k', p', t, m')) as t0 ->
            try remove_aux k' p' m' t with Not_modified -> t0

    let rec second_best m' = function
      | Start -> Void
      | LLoser (_, k, p, l, m, r) -> play (Winner (k, p, l, m)) (second_best m' r)
      | RLoser (_, k, p, l, m, r) -> play (second_best m l) (Winner (k, p, r, m'))

    let remove_min_binding = function
      | Void as t -> t
      | Winner (_, _, t, m) -> second_best m t

    let of_list = List.fold_left (fun t (k, p) -> add k p t) empty

    let fold f =
      let rec fold_aux k p acc = function
        | Start -> f k p acc
        | RLoser (_, k', p', l, _, r) ->
            fold_aux k p (fold_aux k' p' acc r) l
        | LLoser (_, k', p', l, _, r) ->
            fold_aux k' p' (fold_aux k p acc r) l in
      fun t acc ->
        match t with
        | Void -> acc
        | Winner (k, p, t, _) -> fold_aux k p acc t

    let bindings t = fold (fun k p -> List.cons (k, p)) t []
  end

end

module WeightedDirectedGraph = struct
  module Make
    (Vertex : sig
      type t
      val compare : t -> t -> int
    end)
    (Weight : sig
      type t
      val zero : t
      val ( + ) : t -> t -> t
      val compare : t -> t -> int
    end)
  : sig
    type 'a church_list = { fold : 'b. ('a -> 'b -> 'b) -> 'b -> 'b }

    (* ダイクストラ法で最短距離を求める関数 *)
    val dijkstra :
    (* 隣接リスト *)
    (Vertex.t -> (Vertex.t * Weight.t) church_list) ->
    (* 始点 *)
    Vertex.t ->
    (* 始点からの最短距離を返す関数
       始点から辿り着けない場合Noneを返す
       これらの関数を覚えておけば，呼び出しごとの途中までの計算結果がシェアされる *)
    Vertex.t -> Weight.t option
  end = struct
    module VMap = Map.Make (Vertex)
    module PSQ = PrioritySearchQueue.Make (Vertex) (Weight)

    type 'a church_list = { fold : 'b. ('a -> 'b -> 'b) -> 'b -> 'b }

    let dijkstra es s =
      let d = ref VMap.empty in
      let q = ref (PSQ.singleton s Weight.zero) in
      let rec dijkstra_aux t =
        match PSQ.min_binding_opt !q with
        | None -> None
        | Some (u, w) ->
            d := VMap.add u w !d;
            q := PSQ.remove_min_binding !q;
            (es u).fold (fun (v, c) () ->
              if not (VMap.mem v !d) then begin
                let d' = let open Weight in w + c in
                q := PSQ.update v (function
                  | None -> Some d'
                  | (Some d) as o -> if 0 < Weight.compare d d' then Some d' else o) !q
              end) ();
            if Vertex.compare u t = 0
            then Some w
            else dijkstra_aux t in
      fun t -> try Some (VMap.find t !d) with Not_found -> dijkstra_aux t
  end
end

module G = WeightedDirectedGraph.Make
(struct
  type t = int * int
  let compare = compare
end)
(struct
  type t = int
  let zero = 0
  let ( + ) = ( + )
  let compare = compare
end)

let () = Scanf.scanf "%d %d %d\n" @@ fun n m s ->
  let es = Array.make n [] in
  for i = 0 to m - 1 do
    Scanf.scanf "%d %d %d %d\n" @@ fun u v a b ->
      es.(u - 1) <- (v - 1, a, b) :: es.(u - 1);
      es.(v - 1) <- (u - 1, a, b) :: es.(v - 1);
  done;
  let vs = Array.init n @@ fun _ -> Scanf.scanf "%d %d\n" @@ fun c d -> (c, d) in
  let d = Fun.flip G.dijkstra (0, min 2500 s) @@ fun (v, w) ->
    { G.fold = fun g acc ->
      g (let (c, d) = vs.(v) in ((v, min 2500 (w + c)), d)) @@
      List.fold_right (fun (u, a, b) acc ->
        if w < a
        then acc
        else g ((u, w - a), b) acc) es.(v) acc } in
  for v = 1 to n - 1 do
    Printf.printf "%d\n" @@
    List.fold_left min max_int @@
    List.init 2501 @@ fun w -> Option.value ~default:max_int @@ d (v, w)
  done


module WeightedDirectedGraph
: sig
  (* 配列を用いたダイクストラ法の実装
     単純な速さでは一番だが，インターフェースが不便 *)
  module ByArray : sig
    module Make :
      functor
      (* 辺の重さ *)
      (Weight : sig
        type t
        val inf : t
        val zero : t
        val ( + ) : t -> t -> t
        val compare : t -> t -> int
      end)
      (* 道の集合の表現 *)
      (Path : sig
        type t
        (* 辺の名前 *)
        type edge
        (* 長さ0の道だけのsingleton *)
        val nil : t
        (* 空集合 *)
        val empty : t
        (* 与えられた集合に属する道について，それぞれ末尾に辺を付け足した集合 *)
        val snoc : t -> edge -> t
        (* 道の集合のunion
           最短経路は一つだけ分かればよい場合はFun.constを与えるとよい *)
        val union : t -> t -> t
      end) ->
        sig
          type 'a church_list = { fold : 'b. ('a -> 'b -> 'b) -> 'b -> 'b }

          (* 頂点を[0, n)の自然数に限定したグラフに対してのダイクストラ法
             時間計算量O(E log E)なので，疎なグラフなら速い *)
          val dijkstra :
          (* 頂点数n *)
          int ->
          (* 隣接リスト *)
          (int -> (int * Weight.t * Path.edge) church_list) ->
          (* 始点 *)
          int ->
          (* 始点からの最短距離を返す関数と，始点からの最短経路を返す関数の組
             始点から辿り着けない場合，前者はinfを，後者はPath.emptyを返す
             これらの関数を覚えておけば，呼び出しごとの途中までの計算結果がシェアされる *)
          (int -> Weight.t) * (int -> Path.t)

          (* 頂点を[0, n)の自然数に限定したグラフに対してのダイクストラ法
             時間計算量O(V^2)なので，密なグラフなら速い *)
          val dijkstra_dense :
          (* 頂点数n *)
          int ->
          (* 隣接リスト *)
          (int -> (int * Weight.t * Path.edge) church_list) ->
          (* 始点 *)
          int ->
          (* 始点からの最短距離を返す関数と，始点からの最短経路を返す関数の組
             始点から辿り着けない場合，前者はinfを，後者はPath.emptyを返す
             これらの関数を覚えておけば，呼び出しごとの途中までの計算結果がシェアされる *)
          (int -> Weight.t) * (int -> Path.t)
      end
  end

  (* ハッシュテーブルを用いたダイクストラ法の実装
     配列を用いた実装よりは扱いやすいインターフェースを持つ
     ハッシュ関数を上手く選べば配列を用いた実装より1.5倍遅い程度ですむ *)
  module ByHashtbl : sig
    module Make :
      functor
      (* 頂点 *)
      (Vertex : Hashtbl.HashedType)
      (* 辺の重さ *)
      (Weight : sig
        type t
        val inf : t
        val zero : t
        val ( + ) : t -> t -> t
        val compare : t -> t -> int
      end)
      (* 道の集合の表現 *)
      (Path : sig
        type t
        (* 辺の名前 *)
        type edge
        (* 長さ0の道だけのsingleton *)
        val nil : t
        (* 与えられた集合に属する道について，それぞれ末尾に辺を付け足した集合 *)
        val snoc : t -> edge -> t
        (* 道の集合のunion
           最短経路は一つだけ分かればよい場合はFun.constを与えるとよい *)
        val union : t -> t -> t
      end) ->
      sig
        type 'a church_list = { fold : 'b. ('a -> 'b -> 'b) -> 'b -> 'b }

        val dijkstra :
        (* 頂点数（Hashtbl.tを用いるので目安程度） *)
        int ->
        (* 隣接リスト *)
        (Vertex.t -> (Vertex.t * Weight.t * Path.edge) church_list) ->
        (* 始点 *)
        Vertex.t ->
        (* 始点からの最短距離を返す関数と，始点からの最短経路を返す関数の組
           両者とも始点から辿り着けなければNot_foundを投げる
           これらの関数を覚えておけば，呼び出しごとの途中までの計算結果がシェアされる *)
        (Vertex.t -> Weight.t) * (Vertex.t -> Path.t)
      end
  end

  (* Mapを用いたダイクストラ法の実装
     配列を用いた実装より4倍ぐらい遅いが，
     一番扱いやすいインターフェースを持ち，無限グラフにも対応可能 *)
  module ByMap : sig
    module Make :
      functor
      (* 頂点 *)
      (Vertex : Map.OrderedType)
      (* 辺の重み *)
      (Weight : sig
        type t
        val zero : t
        val ( + ) : t -> t -> t
        val compare : t -> t -> int
      end)
      (* 道の集合の表現 *)
      (Path : sig
        type t
        (* 辺の名前 *)
        type edge
        (* 長さ0の道だけのsingleton *)
        val nil : t
        (* 与えられた集合に属する道について，それぞれ末尾に辺を付け足した集合 *)
        val snoc : t -> edge -> t
        (* 道の集合のunion
           最短経路は一つだけ分かればよい場合はFun.constを与えるとよい *)
        val union : t -> t -> t
      end) ->
      sig
        type 'a church_list = { fold : 'b. ('a -> 'b -> 'b) -> 'b -> 'b }

        val dijkstra :
        (* 隣接リスト *)
        (Vertex.t -> (Vertex.t * Weight.t * Path.edge) church_list) ->
        (* 始点 *)
        Vertex.t ->
        (* 始点からの最短距離を返す関数と，始点からの最短経路を返す関数の組
           両者とも始点から辿り着けなければNot_foundを投げる
           これらの関数を覚えておけば，呼び出しごとの途中までの計算結果がシェアされる *)
        (Vertex.t -> Weight.t) * (Vertex.t -> Path.t)
      end
  end
end
= struct
  module type Weight = sig
    type t
    val zero : t
    val ( + ) : t -> t -> t
    val compare : t -> t -> int
  end

  module type Path = sig
    type t
    type edge
    val nil : t
    val snoc : t -> edge -> t
    val union : t -> t -> t
  end

  (* 最短距離を格納するデータ構造を抽象化したダイクストラ法の実装 *)
  module Core
    (W : Weight)
    (P : Path)
    (* グラフの頂点を添字とした配列 *)
    (VArray : sig
      type t
      type vertex (* グラフの頂点 *)
      val find : t -> vertex -> W.t * P.t (* 最短距離が格納されていなければNot_foundを投げる *)
      val update : t -> vertex -> W.t * P.t -> unit
    end) =
  struct
    type 'a church_list = { fold : 'b. ('a -> 'b -> 'b) -> 'b -> 'b }

    module WMap = Map.Make (W)

    let dijkstra d es s =
      VArray.update d s (W.zero, P.nil);
      let q = ref (WMap.singleton W.zero [s]) in
      (* 既に最短距離が確定した辺へのクエリを高速化するため，
         ヒープの最小要素をメモしておく *)
      let min_binding_opt = ref (Some (W.zero, [s])) in
      let rec dijkstra_aux t =
        match !min_binding_opt with
        (* もう既に全ての頂点までの距離が分かっている *)
        | None -> VArray.find d t
        | Some (w, us) ->
            match VArray.find d t with
            (* 既に終点までの距離と，全ての最短経路が分かっているので返す *)
            | (x, _) as ans when W.compare x w < 0 -> ans
            (* 終点までの距離が分かっていないので，ダイクストラ法を続行 *)
            | _ | exception Not_found ->
                q := WMap.remove w !q;
                Fun.flip List.iter us (fun u ->
                  match VArray.find d u with
                  | (d, _) when 0 < W.compare w d -> ()
                  | (_, pu) ->
                      (* 未だ頂点uを訪れていない *)
                      Fun.flip (es u).fold () @@ fun (v, c, e) () ->
                        let dv' = let open W in w + c in
                        match VArray.find d v with
                        | (dv, _) when W.compare dv dv' < 0 -> ()
                        | (dv, pv) when W.compare dv dv' = 0 ->
                            (* 新しい最短経路を見つけたので追加 *)
                            let pv' = P.union pv (P.snoc pu e) in
                            if pv != pv' then VArray.update d v (dv, pv')
                        | _ | exception Not_found ->
                            VArray.update d v (dv', P.snoc pu e);
                            q := WMap.update dv' (fun vs -> Some (v :: Option.value ~default:[] vs)) !q);
                min_binding_opt := WMap.min_binding_opt !q;
                dijkstra_aux t in
      (fun v -> fst @@ dijkstra_aux v),
      (fun v -> snd @@ dijkstra_aux v)
  end

  module ByArray = struct
    module Make (W : sig include Weight val inf : t end) (P : sig include Path val empty : t end) = struct
      type 'a church_list = { fold : 'b. ('a -> 'b -> 'b) -> 'b -> 'b }

      module WMap = Map.Make (W)

      let dijkstra n es s =
        let d = Array.make n W.inf in
        let r = Array.make n P.empty in
        let q = ref (WMap.singleton W.zero [s]) in
        (* 既に最短距離が確定した辺へのクエリを高速化するため，
           ヒープの最小要素をメモしておく *)
        let min_binding_opt = ref (Some (W.zero, [s])) in
        r.(s) <- P.nil;
        d.(s) <- W.zero;
        let dijkstra_aux w us =
          q := WMap.remove w !q;
          List.iter (fun u ->
            if 0 <= W.compare d.(u) w then
              (* 未だ頂点uを訪れていない *)
              Fun.flip (es u).fold () @@ fun (v, c, e) () ->
                let dv' = let open W in w + c in
                match W.compare d.(v) dv' with
                | x when x < 0 -> ()
                (* 新しい最短経路を見つけたので追加 *)
                | 0 -> r.(v) <- P.union r.(v) (P.snoc r.(u) e)
                | _ ->
                    d.(v) <- dv';
                    r.(v) <- P.snoc r.(u) e;
                    q := WMap.update dv' (fun vs -> Some (v :: Option.value ~default:[] vs)) !q) us;
          min_binding_opt := WMap.min_binding_opt !q in
        let rec distance t =
          match !min_binding_opt with
          (* もう既に全ての頂点までの距離が分かっている *)
          | None -> d.(t)
          | Some (w, us) ->
              if W.compare d.(t) w <= 0
              (* 既に終点までの距離が分かっているので返す *)
              then d.(t)
              (* 終点までの距離が分かっていないので，ダイクストラ法を続行 *)
              else (dijkstra_aux w us; distance t) in
        let rec path t =
          match !min_binding_opt with
          (* もう既に全ての頂点までの最短経路が分かっている *)
          | None -> r.(t)
          | Some (w, us) ->
              if W.compare d.(t) w < 0
              (* 既に終点までの全ての最短経路が分かっているので返す *)
              then r.(t)
              (* 終点までの距離が分かっていないので，ダイクストラ法を続行 *)
              else (dijkstra_aux w us; path t) in
        distance, path

      let dijkstra_dense n es s =
        let d = Array.make n W.inf in
        let r = Array.make n P.empty in
        r.(s) <- P.nil;
        d.(s) <- W.zero;
        let rec dijkstra_dense_aux = function
          | [] -> ()
          | v :: vs ->
              let u, us = List.fold_left (fun (u, us) v ->
                if W.compare d.(u) d.(v) < 0
                then (u, v :: us)
                else (v, u :: us)) (v, []) vs in
              (es u).fold (fun (v, c, e) () ->
                let dv' = let open W in d.(u) + c in
                match W.compare d.(v) dv' with
                | x when x < 0 -> ()
                | 0 -> r.(v) <- P.union r.(v) (P.snoc r.(u) e)
                | _ -> d.(v) <- dv'; r.(v) <- P.snoc r.(u) e) ();
              dijkstra_dense_aux us in
        dijkstra_dense_aux (List.init n Fun.id);
        (Array.get d, Array.get r)
      end
  end

  module ByHashtbl = struct
    module Make (V : Hashtbl.HashedType) (W : Weight) (P : Path) = struct
      module VHash = Hashtbl.Make (V)
      module C = Core (W) (P) (struct
        type t = (W.t * P.t) VHash.t
        type vertex = V.t
        let find = VHash.find
        let update = VHash.replace
      end)
      include C

      let dijkstra n e s = C.dijkstra (VHash.create n) e s
    end
  end

  module ByMap = struct
    module Make (V : Map.OrderedType) (W : Weight) (P : Path) = struct
      module VMap = Map.Make (V)
      module C = Core (W) (P) (struct
        type t = (W.t * P.t) VMap.t ref
        type vertex = V.t
        let find d v = VMap.find v !d
        let update d v w = d := VMap.add v w !d
      end)
      include C

      let dijkstra e s = C.dijkstra (ref VMap.empty) e s
    end
  end
end

module IntWeightedDirectedGraphByArray = struct
  module Make
    (Path : sig
      type t
      type edge
      val nil : t
      val empty : t
      val snoc : t -> edge -> t
      val union : t -> t -> t
    end)
  = struct
    include (WeightedDirectedGraph.ByArray.Make (struct
      type t = int
      let zero = 0
      let inf = max_int
      let ( + ) = ( + )
      let compare = compare
    end) (Path))

    (* 辺の重さがごく小さい整数の場合は，Mapをキュー代わりに使うより配列を使った方が効率的
       時間計算量はO(E+VW)，空間計算量はO(E+W) *)
    let dijkstra_special :
      (* 頂点数n *)
      int ->
      (* 辺の重さの上限W *)
      int ->
      (* 頂点uを受け取って，
         uから伸びる辺の終点vと重さwの組みのリストを返す関数
         辺の重さwはW以下でなくてはならない *)
      (int -> (int * int * Path.edge) church_list) ->
      (* 始点 *)
      int ->
      (* 始点からの最短距離を返す関数と，始点からの最短経路を返す関数の組
         始点から辿り着けない場合，前者はinfを，後者はPath.emptyを返す
         これらの関数を覚えておけば，呼び出しごとの途中までの計算結果がシェアされる *)
      (int -> int) * (int -> Path.t)
    = fun n mw es s ->
      (* 各頂点への最短距離を格納するやつ *)
      let d = Array.make n max_int in
      (* 各頂点への最短経路を格納するやつ *)
      let r = Array.make n Path.nil in
      (* キュー *)
      let q = Array.make (mw + 1) [] in
      (* ヒープの最小要素の重み *)
      let w = ref 0 in
      (* ヒープの最小要素がどのインデックスに対応するか *)
      let i = ref 0 in
      (* ヒープに格納されている要素の数 *)
      let m = ref 1 in
      d.(s) <- 0;
      q.(0) <- [s];
      let rec dijkstra_aux t =
        (* 既に終点までの距離が分かっているので返す *)
        if !m <= 0 || d.(t) <= !w then (d.(t), r.(t)) else
        match q.(!i) with
        (* ヒープには重さがwの要素は無かった *)
        | [] ->
            incr w;
            incr i;
            if mw < !i then i := 0;
            dijkstra_aux t
        (* ヒープには重さwの要素uが存在する *)
        | u :: us ->
            (* ヒープから重さwの要素を削除する *)
            decr m;
            q.(!i) <- us;
            if !w <= d.(u) then
              (* 未だ頂点uを訪れていない *)
              (es u).fold (fun (v, c, e) () ->
                match compare d.(v) (!w + c) with
                | x when x < 0 -> ()
                | 0 -> r.(v) <- Path.union r.(v) (Path.snoc r.(u) e);
                | _ ->
                    d.(v) <- !w + c; (* 頂点vの重さを緩和 *)
                    r.(v) <- Path.snoc r.(u) e;
                    (* ヒープにvを追加する *)
                    let j = !i + c - if !i + c <= mw then 0 else mw + 1 in
                    q.(j) <- v :: q.(j);
                    incr m) ();
            dijkstra_aux t in
      (fun v -> fst @@ dijkstra_aux v),
      (fun v -> snd @@ dijkstra_aux v)
  end
end

module G = WeightedDirectedGraph.ByMap.Make
(struct
  type t = int * int
  let compare = compare
end)
(struct
  type t = int
  let zero = 0
  let ( + ) = ( + )
  let compare = compare
end)
(struct
  type t = unit
  type edge = unit
  let nil = ()
  let snoc _ _ = ()
  let union = Fun.const
end)

let () = Scanf.scanf "%d %d %d\n" @@ fun n m s ->
  let es = Array.make n [] in
  for i = 0 to m - 1 do
    Scanf.scanf "%d %d %d %d\n" @@ fun u v a b ->
      es.(u - 1) <- (v - 1, a, b) :: es.(u - 1);
      es.(v - 1) <- (u - 1, a, b) :: es.(v - 1);
  done;
  let vs = Array.init n @@ fun _ -> Scanf.scanf "%d %d\n" @@ fun c d -> (c, d) in
  let d, _ = Fun.flip G.dijkstra (0, min 2500 s) @@ fun (v, w) ->
    { G.fold = fun g acc ->
      g (let (c, d) = vs.(v) in ((v, min 2500 (w + c)), d, ())) @@
      List.fold_right (fun (u, a, b) acc ->
        if w < a
        then acc
        else g ((u, w - a), b, ()) acc) es.(v) acc } in
  for v = 1 to n - 1 do
    Printf.printf "%d\n" @@
    List.fold_left min max_int @@
    List.init 2501 @@ fun w -> try d (v, w) with Not_found -> max_int
  done


module WeightedDirectedGraph
: sig
  (* 配列を用いたダイクストラ法の実装
     単純な速さでは一番だが，インターフェースが不便 *)
  module ByArray : sig
    module Make :
      functor
      (* 辺の重さ *)
      (Weight : sig
        type t
        val inf : t
        val zero : t
        val ( + ) : t -> t -> t
        val compare : t -> t -> int
      end)
      (* 道の集合の表現 *)
      (Path : sig
        type t
        (* 辺の名前 *)
        type edge
        (* 長さ0の道だけのsingleton *)
        val nil : t
        (* 空集合 *)
        val empty : t
        (* 与えられた集合に属する道について，それぞれ末尾に辺を付け足した集合 *)
        val snoc : t -> edge -> t
        (* 道の集合のunion
           最短経路は一つだけ分かればよい場合はFun.constを与えるとよい *)
        val union : t -> t -> t
      end) ->
        sig
          type 'a church_list = { fold : 'b. ('a -> 'b -> 'b) -> 'b -> 'b }

          (* 頂点を[0, n)の自然数に限定したグラフに対してのダイクストラ法
             時間計算量O(E log E)なので，疎なグラフなら速い *)
          val dijkstra :
          (* 頂点数n *)
          int ->
          (* 隣接リスト *)
          (int -> (int * Weight.t * Path.edge) church_list) ->
          (* 始点 *)
          int ->
          (* 始点からの最短距離を返す関数と，始点からの最短経路を返す関数の組
             始点から辿り着けない場合，前者はinfを，後者はPath.emptyを返す
             これらの関数を覚えておけば，呼び出しごとの途中までの計算結果がシェアされる *)
          (int -> Weight.t) * (int -> Path.t)

          (* 頂点を[0, n)の自然数に限定したグラフに対してのダイクストラ法
             時間計算量O(V^2)なので，密なグラフなら速い *)
          val dijkstra_dense :
          (* 頂点数n *)
          int ->
          (* 隣接リスト *)
          (int -> (int * Weight.t * Path.edge) church_list) ->
          (* 始点 *)
          int ->
          (* 始点からの最短距離を返す関数と，始点からの最短経路を返す関数の組
             始点から辿り着けない場合，前者はinfを，後者はPath.emptyを返す
             これらの関数を覚えておけば，呼び出しごとの途中までの計算結果がシェアされる *)
          (int -> Weight.t) * (int -> Path.t)
      end
  end

  (* ハッシュテーブルを用いたダイクストラ法の実装
     配列を用いた実装よりは扱いやすいインターフェースを持つ
     ハッシュ関数を上手く選べば配列を用いた実装より1.5倍遅い程度ですむ *)
  module ByHashtbl : sig
    module Make :
      functor
      (* 頂点 *)
      (Vertex : Hashtbl.HashedType)
      (* 辺の重さ *)
      (Weight : sig
        type t
        val inf : t
        val zero : t
        val ( + ) : t -> t -> t
        val compare : t -> t -> int
      end)
      (* 道の集合の表現 *)
      (Path : sig
        type t
        (* 辺の名前 *)
        type edge
        (* 長さ0の道だけのsingleton *)
        val nil : t
        (* 与えられた集合に属する道について，それぞれ末尾に辺を付け足した集合 *)
        val snoc : t -> edge -> t
        (* 道の集合のunion
           最短経路は一つだけ分かればよい場合はFun.constを与えるとよい *)
        val union : t -> t -> t
      end) ->
      sig
        type 'a church_list = { fold : 'b. ('a -> 'b -> 'b) -> 'b -> 'b }

        val dijkstra :
        (* 頂点数（Hashtbl.tを用いるので目安程度） *)
        int ->
        (* 隣接リスト *)
        (Vertex.t -> (Vertex.t * Weight.t * Path.edge) church_list) ->
        (* 始点 *)
        Vertex.t ->
        (* 始点からの最短距離を返す関数と，始点からの最短経路を返す関数の組
           両者とも始点から辿り着けなければNot_foundを投げる
           これらの関数を覚えておけば，呼び出しごとの途中までの計算結果がシェアされる *)
        (Vertex.t -> Weight.t) * (Vertex.t -> Path.t)
      end
  end

  (* Mapを用いたダイクストラ法の実装
     配列を用いた実装より4倍ぐらい遅いが，
     一番扱いやすいインターフェースを持ち，無限グラフにも対応可能 *)
  module ByMap : sig
    module Make :
      functor
      (* 頂点 *)
      (Vertex : Map.OrderedType)
      (* 辺の重み *)
      (Weight : sig
        type t
        val zero : t
        val ( + ) : t -> t -> t
        val compare : t -> t -> int
      end)
      (* 道の集合の表現 *)
      (Path : sig
        type t
        (* 辺の名前 *)
        type edge
        (* 長さ0の道だけのsingleton *)
        val nil : t
        (* 与えられた集合に属する道について，それぞれ末尾に辺を付け足した集合 *)
        val snoc : t -> edge -> t
        (* 道の集合のunion
           最短経路は一つだけ分かればよい場合はFun.constを与えるとよい *)
        val union : t -> t -> t
      end) ->
      sig
        type 'a church_list = { fold : 'b. ('a -> 'b -> 'b) -> 'b -> 'b }

        val dijkstra :
        (* 隣接リスト *)
        (Vertex.t -> (Vertex.t * Weight.t * Path.edge) church_list) ->
        (* 始点 *)
        Vertex.t ->
        (* 始点からの最短距離を返す関数と，始点からの最短経路を返す関数の組
           両者とも始点から辿り着けなければNot_foundを投げる
           これらの関数を覚えておけば，呼び出しごとの途中までの計算結果がシェアされる *)
        (Vertex.t -> Weight.t) * (Vertex.t -> Path.t)
      end
  end
end
= struct
  module type Weight = sig
    type t
    val zero : t
    val ( + ) : t -> t -> t
    val compare : t -> t -> int
  end

  module type Path = sig
    type t
    type edge
    val nil : t
    val snoc : t -> edge -> t
    val union : t -> t -> t
  end

  (* 最短距離を格納するデータ構造を抽象化したダイクストラ法の実装 *)
  module Core
    (W : Weight)
    (P : Path)
    (* グラフの頂点を添字とした配列 *)
    (VArray : sig
      type t
      type vertex (* グラフの頂点 *)
      val find : t -> vertex -> W.t * P.t (* 最短距離が格納されていなければNot_foundを投げる *)
      val update : t -> vertex -> W.t * P.t -> unit
    end) =
  struct
    type 'a church_list = { fold : 'b. ('a -> 'b -> 'b) -> 'b -> 'b }

    module WMap = Map.Make (W)

    let dijkstra d es s =
      VArray.update d s (W.zero, P.nil);
      let q = ref (WMap.singleton W.zero [s]) in
      (* 既に最短距離が確定した辺へのクエリを高速化するため，
         ヒープの最小要素をメモしておく *)
      let min_binding_opt = ref (Some (W.zero, [s])) in
      let dijkstra_aux w us =
        q := WMap.remove w !q;
        Fun.flip List.iter us (fun u ->
          match VArray.find d u with
          | (d, _) when 0 < W.compare w d -> ()
          | (_, pu) ->
              (* 未だ頂点uを訪れていない *)
              Fun.flip (es u).fold () @@ fun (v, c, e) () ->
                let dv' = let open W in w + c in
                match VArray.find d v with
                | (dv, _) when W.compare dv dv' < 0 -> ()
                | (dv, pv) when W.compare dv dv' = 0 ->
                    (* 新しい最短経路を見つけたので追加 *)
                    let pv' = P.union pv (P.snoc pu e) in
                    if pv != pv' then VArray.update d v (dv, pv')
                | _ | exception Not_found ->
                    VArray.update d v (dv', P.snoc pu e);
                    q := WMap.update dv' (fun vs -> Some (v :: Option.value ~default:[] vs)) !q);
        min_binding_opt := WMap.min_binding_opt !q in
      let rec distance t =
        match !min_binding_opt with
        (* もう既に全ての頂点までの距離が分かっている *)
        | None -> fst @@ VArray.find d t
        | Some (w, us) ->
            match VArray.find d t with
            (* 既に終点までの距離が分かっているので返す *)
            | (x, _) when W.compare x w <= 0 -> x
            (* 終点までの距離が分かっていないので，ダイクストラ法を続行 *)
            | _ | exception Not_found -> dijkstra_aux w us; distance t in
      let rec path t =
        match !min_binding_opt with
        (* もう既に全ての頂点までの最短距離が分かっている *)
        | None -> snd @@ VArray.find d t
        | Some (w, us) ->
            match VArray.find d t with
            (* 既に終点までの全ての最短経路が分かっているので返す *)
            | (x, p) when W.compare x w < 0 -> p
            (* 終点までの距離が全て分かっているわけではないので，ダイクストラ法を続行 *)
            | _ | exception Not_found -> dijkstra_aux w us; path t in
      distance, path
  end

  module ByArray = struct
    module Make (W : sig include Weight val inf : t end) (P : sig include Path val empty : t end) = struct
      type 'a church_list = { fold : 'b. ('a -> 'b -> 'b) -> 'b -> 'b }

      module WMap = Map.Make (W)

      let dijkstra n es s =
        let d = Array.make n W.inf in
        let r = Array.make n P.empty in
        let q = ref (WMap.singleton W.zero [s]) in
        (* 既に最短距離が確定した辺へのクエリを高速化するため，
           ヒープの最小要素をメモしておく *)
        let min_binding_opt = ref (Some (W.zero, [s])) in
        r.(s) <- P.nil;
        d.(s) <- W.zero;
        let dijkstra_aux w us =
          q := WMap.remove w !q;
          List.iter (fun u ->
            if 0 <= W.compare d.(u) w then
              (* 未だ頂点uを訪れていない *)
              Fun.flip (es u).fold () @@ fun (v, c, e) () ->
                let dv' = let open W in w + c in
                match W.compare d.(v) dv' with
                | x when x < 0 -> ()
                (* 新しい最短経路を見つけたので追加 *)
                | 0 -> r.(v) <- P.union r.(v) (P.snoc r.(u) e)
                | _ ->
                    d.(v) <- dv';
                    r.(v) <- P.snoc r.(u) e;
                    q := WMap.update dv' (fun vs -> Some (v :: Option.value ~default:[] vs)) !q) us;
          min_binding_opt := WMap.min_binding_opt !q in
        let rec distance t =
          match !min_binding_opt with
          (* もう既に全ての頂点までの距離が分かっている *)
          | None -> d.(t)
          | Some (w, us) ->
              if W.compare d.(t) w <= 0
              (* 既に終点までの距離が分かっているので返す *)
              then d.(t)
              (* 終点までの距離が分かっていないので，ダイクストラ法を続行 *)
              else (dijkstra_aux w us; distance t) in
        let rec path t =
          match !min_binding_opt with
          (* もう既に全ての頂点までの最短経路が分かっている *)
          | None -> r.(t)
          | Some (w, us) ->
              if W.compare d.(t) w < 0
              (* 既に終点までの全ての最短経路が分かっているので返す *)
              then r.(t)
              (* 終点までの距離が分かっていないので，ダイクストラ法を続行 *)
              else (dijkstra_aux w us; path t) in
        distance, path

      let dijkstra_dense n es s =
        let d = Array.make n W.inf in
        let r = Array.make n P.empty in
        r.(s) <- P.nil;
        d.(s) <- W.zero;
        let rec dijkstra_dense_aux = function
          | [] -> ()
          | v :: vs ->
              let u, us = List.fold_left (fun (u, us) v ->
                if W.compare d.(u) d.(v) < 0
                then (u, v :: us)
                else (v, u :: us)) (v, []) vs in
              (es u).fold (fun (v, c, e) () ->
                let dv' = let open W in d.(u) + c in
                match W.compare d.(v) dv' with
                | x when x < 0 -> ()
                | 0 -> r.(v) <- P.union r.(v) (P.snoc r.(u) e)
                | _ -> d.(v) <- dv'; r.(v) <- P.snoc r.(u) e) ();
              dijkstra_dense_aux us in
        dijkstra_dense_aux (List.init n Fun.id);
        (Array.get d, Array.get r)
      end
  end

  module ByHashtbl = struct
    module Make (V : Hashtbl.HashedType) (W : Weight) (P : Path) = struct
      module VHash = Hashtbl.Make (V)
      module C = Core (W) (P) (struct
        type t = (W.t * P.t) VHash.t
        type vertex = V.t
        let find = VHash.find
        let update = VHash.replace
      end)
      include C

      let dijkstra n e s = C.dijkstra (VHash.create n) e s
    end
  end

  module ByMap = struct
    module Make (V : Map.OrderedType) (W : Weight) (P : Path) = struct
      module VMap = Map.Make (V)
      module C = Core (W) (P) (struct
        type t = (W.t * P.t) VMap.t ref
        type vertex = V.t
        let find d v = VMap.find v !d
        let update d v w = d := VMap.add v w !d
      end)
      include C

      let dijkstra e s = C.dijkstra (ref VMap.empty) e s
    end
  end
end

module IntWeightedDirectedGraphByArray = struct
  module Make
    (Path : sig
      type t
      type edge
      val nil : t
      val empty : t
      val snoc : t -> edge -> t
      val union : t -> t -> t
    end)
  = struct
    include (WeightedDirectedGraph.ByArray.Make (struct
      type t = int
      let zero = 0
      let inf = max_int
      let ( + ) = ( + )
      let compare = compare
    end) (Path))

    (* 辺の重さがごく小さい整数の場合は，Mapをキュー代わりに使うより配列を使った方が効率的
       時間計算量はO(E+VW)，空間計算量はO(E+W) *)
    let dijkstra_special :
      (* 頂点数n *)
      int ->
      (* 辺の重さの上限W *)
      int ->
      (* 頂点uを受け取って，
         uから伸びる辺の終点vと重さwの組みのリストを返す関数
         辺の重さwはW以下でなくてはならない *)
      (int -> (int * int * Path.edge) church_list) ->
      (* 始点 *)
      int ->
      (* 始点からの最短距離を返す関数と，始点からの最短経路を返す関数の組
         始点から辿り着けない場合，前者はinfを，後者はPath.emptyを返す
         これらの関数を覚えておけば，呼び出しごとの途中までの計算結果がシェアされる *)
      (int -> int) * (int -> Path.t)
    = fun n mw es s ->
      (* 各頂点への最短距離を格納するやつ *)
      let d = Array.make n max_int in
      (* 各頂点への最短経路を格納するやつ *)
      let r = Array.make n Path.nil in
      (* キュー *)
      let q = Array.make (mw + 1) [] in
      (* ヒープの最小要素の重み *)
      let w = ref 0 in
      (* ヒープの最小要素がどのインデックスに対応するか *)
      let i = ref 0 in
      (* ヒープに格納されている要素の数 *)
      let m = ref 1 in
      d.(s) <- 0;
      q.(0) <- [s];
      let rec dijkstra_aux t =
        (* 既に終点までの距離が分かっているので返す *)
        if !m <= 0 || d.(t) <= !w then (d.(t), r.(t)) else
        match q.(!i) with
        (* ヒープには重さがwの要素は無かった *)
        | [] ->
            incr w;
            incr i;
            if mw < !i then i := 0;
            dijkstra_aux t
        (* ヒープには重さwの要素uが存在する *)
        | u :: us ->
            (* ヒープから重さwの要素を削除する *)
            decr m;
            q.(!i) <- us;
            if !w <= d.(u) then
              (* 未だ頂点uを訪れていない *)
              (es u).fold (fun (v, c, e) () ->
                match compare d.(v) (!w + c) with
                | x when x < 0 -> ()
                | 0 -> r.(v) <- Path.union r.(v) (Path.snoc r.(u) e);
                | _ ->
                    d.(v) <- !w + c; (* 頂点vの重さを緩和 *)
                    r.(v) <- Path.snoc r.(u) e;
                    (* ヒープにvを追加する *)
                    let j = !i + c - if !i + c <= mw then 0 else mw + 1 in
                    q.(j) <- v :: q.(j);
                    incr m) ();
            dijkstra_aux t in
      (fun v -> fst @@ dijkstra_aux v),
      (fun v -> snd @@ dijkstra_aux v)
  end
end

module G = WeightedDirectedGraph.ByMap.Make
(struct
  type t = int * int
  let compare = compare
end)
(struct
  type t = int
  let zero = 0
  let ( + ) = ( + )
  let compare = compare
end)
(struct
  type t = unit
  type edge = unit
  let nil = ()
  let snoc _ _ = ()
  let union = Fun.const
end)

let () = Scanf.scanf "%d %d %d\n" @@ fun n m s ->
  let es = Array.make n [] in
  for i = 0 to m - 1 do
    Scanf.scanf "%d %d %d %d\n" @@ fun u v a b ->
      es.(u - 1) <- (v - 1, a, b) :: es.(u - 1);
      es.(v - 1) <- (u - 1, a, b) :: es.(v - 1);
  done;
  let vs = Array.init n @@ fun _ -> Scanf.scanf "%d %d\n" @@ fun c d -> (c, d) in
  let d, _ = Fun.flip G.dijkstra (0, min 2500 s) @@ fun (v, w) ->
    { G.fold = fun g acc ->
      g (let (c, d) = vs.(v) in ((v, min 2500 (w + c)), d, ())) @@
      List.fold_right (fun (u, a, b) acc ->
        if w < a
        then acc
        else g ((u, w - a), b, ()) acc) es.(v) acc } in
  for v = 1 to n - 1 do
    Printf.printf "%d\n" @@
    List.fold_left min max_int @@
    List.init 2501 @@ fun w -> try d (v, w) with Not_found -> max_int
  done


module WeightedDirectedGraph
: sig
  (* 配列を用いたダイクストラ法の実装
     単純な速さでは一番だが，インターフェースが不便 *)
  module ByArray : sig
    module Make :
      functor
      (* 辺の重さ *)
      (Weight : sig
        type t
        val inf : t
        val zero : t
        val ( + ) : t -> t -> t
        val compare : t -> t -> int
      end)
      (* 道の集合の表現 *)
      (Path : sig
        type t
        (* 辺の名前 *)
        type edge
        (* 長さ0の道だけのsingleton *)
        val nil : t
        (* 空集合 *)
        val empty : t
        (* 与えられた集合に属する道について，それぞれ末尾に辺を付け足した集合 *)
        val snoc : t -> edge -> t
        (* 道の集合のunion
           最短経路は一つだけ分かればよい場合はFun.constを与えるとよい *)
        val union : t -> t -> t
      end) ->
        sig
          type 'a church_list = { fold : 'b. ('a -> 'b -> 'b) -> 'b -> 'b }

          (* 頂点を[0, n)の自然数に限定したグラフに対してのダイクストラ法
             時間計算量O(E log E)なので，疎なグラフなら速い *)
          val dijkstra :
          (* 頂点数n *)
          int ->
          (* 隣接リスト *)
          (int -> (int * Weight.t * Path.edge) church_list) ->
          (* 始点 *)
          int ->
          (* 始点からの最短距離を返す関数と，始点からの最短経路を返す関数の組
             始点から辿り着けない場合，前者はinfを，後者はPath.emptyを返す
             これらの関数を覚えておけば，呼び出しごとの途中までの計算結果がシェアされる *)
          (int -> Weight.t) * (int -> Path.t)

          (* 頂点を[0, n)の自然数に限定したグラフに対してのダイクストラ法
             時間計算量O(V^2)なので，密なグラフなら速い *)
          val dijkstra_dense :
          (* 頂点数n *)
          int ->
          (* 隣接リスト *)
          (int -> (int * Weight.t * Path.edge) church_list) ->
          (* 始点 *)
          int ->
          (* 始点からの最短距離を返す関数と，始点からの最短経路を返す関数の組
             始点から辿り着けない場合，前者はinfを，後者はPath.emptyを返す
             これらの関数を覚えておけば，呼び出しごとの途中までの計算結果がシェアされる *)
          (int -> Weight.t) * (int -> Path.t)
      end
  end

  (* ハッシュテーブルを用いたダイクストラ法の実装
     配列を用いた実装よりは扱いやすいインターフェースを持つ
     ハッシュ関数を上手く選べば配列を用いた実装より1.5倍遅い程度ですむ *)
  module ByHashtbl : sig
    module Make :
      functor
      (* 頂点 *)
      (Vertex : Hashtbl.HashedType)
      (* 辺の重さ *)
      (Weight : sig
        type t
        val inf : t
        val zero : t
        val ( + ) : t -> t -> t
        val compare : t -> t -> int
      end)
      (* 道の集合の表現 *)
      (Path : sig
        type t
        (* 辺の名前 *)
        type edge
        (* 長さ0の道だけのsingleton *)
        val nil : t
        (* 与えられた集合に属する道について，それぞれ末尾に辺を付け足した集合 *)
        val snoc : t -> edge -> t
        (* 道の集合のunion
           最短経路は一つだけ分かればよい場合はFun.constを与えるとよい *)
        val union : t -> t -> t
      end) ->
      sig
        type 'a church_list = { fold : 'b. ('a -> 'b -> 'b) -> 'b -> 'b }

        val dijkstra :
        (* 頂点数（Hashtbl.tを用いるので目安程度） *)
        int ->
        (* 隣接リスト *)
        (Vertex.t -> (Vertex.t * Weight.t * Path.edge) church_list) ->
        (* 始点 *)
        Vertex.t ->
        (* 始点からの最短距離を返す関数と，始点からの最短経路を返す関数の組
           両者とも始点から辿り着けなければNot_foundを投げる
           これらの関数を覚えておけば，呼び出しごとの途中までの計算結果がシェアされる *)
        (Vertex.t -> Weight.t) * (Vertex.t -> Path.t)
      end
  end

  (* Mapを用いたダイクストラ法の実装
     配列を用いた実装より4倍ぐらい遅いが，
     一番扱いやすいインターフェースを持ち，無限グラフにも対応可能 *)
  module ByMap : sig
    module Make :
      functor
      (* 頂点 *)
      (Vertex : Map.OrderedType)
      (* 辺の重み *)
      (Weight : sig
        type t
        val zero : t
        val ( + ) : t -> t -> t
        val compare : t -> t -> int
      end)
      (* 道の集合の表現 *)
      (Path : sig
        type t
        (* 辺の名前 *)
        type edge
        (* 長さ0の道だけのsingleton *)
        val nil : t
        (* 与えられた集合に属する道について，それぞれ末尾に辺を付け足した集合 *)
        val snoc : t -> edge -> t
        (* 道の集合のunion
           最短経路は一つだけ分かればよい場合はFun.constを与えるとよい *)
        val union : t -> t -> t
      end) ->
      sig
        type 'a church_list = { fold : 'b. ('a -> 'b -> 'b) -> 'b -> 'b }

        val dijkstra :
        (* 隣接リスト *)
        (Vertex.t -> (Vertex.t * Weight.t * Path.edge) church_list) ->
        (* 始点 *)
        Vertex.t ->
        (* 始点からの最短距離を返す関数と，始点からの最短経路を返す関数の組
           両者とも始点から辿り着けなければNot_foundを投げる
           これらの関数を覚えておけば，呼び出しごとの途中までの計算結果がシェアされる *)
        (Vertex.t -> Weight.t) * (Vertex.t -> Path.t)
      end
  end
end
= struct
  module type Weight = sig
    type t
    val zero : t
    val ( + ) : t -> t -> t
    val compare : t -> t -> int
  end

  module type Path = sig
    type t
    type edge
    val nil : t
    val snoc : t -> edge -> t
    val union : t -> t -> t
  end

  (* 最短距離を格納するデータ構造を抽象化したダイクストラ法の実装 *)
  module Core
    (W : Weight)
    (P : Path)
    (* グラフの頂点を添字とした配列 *)
    (VArray : sig
      type t
      type vertex (* グラフの頂点 *)
      val find : t -> vertex -> W.t * P.t (* 最短距離が格納されていなければNot_foundを投げる *)
      val update : t -> vertex -> W.t * P.t -> unit
    end) =
  struct
    type 'a church_list = { fold : 'b. ('a -> 'b -> 'b) -> 'b -> 'b }

    module WMap = Map.Make (W)

    let dijkstra d es s =
      VArray.update d s (W.zero, P.nil);
      let q = ref (WMap.singleton W.zero [s]) in
      (* 既に最短距離が確定した辺へのクエリを高速化するため，
         ヒープの最小要素をメモしておく *)
      let min_binding_opt = ref (Some (W.zero, [s])) in
      let rec dijkstra_aux t =
        match !min_binding_opt with
        (* もう既に全ての頂点までの距離が分かっている *)
        | None -> VArray.find d t
        | Some (w, us) ->
            match VArray.find d t with
            (* 既に終点までの距離と，全ての最短経路が分かっているので返す *)
            | (x, _) as ans when W.compare x w < 0 -> ans
            (* 終点までの距離が分かっていないので，ダイクストラ法を続行 *)
            | _ | exception Not_found ->
                q := WMap.remove w !q;
                Fun.flip List.iter us (fun u ->
                  match VArray.find d u with
                  | (d, _) when 0 < W.compare w d -> ()
                  | (_, pu) ->
                      (* 未だ頂点uを訪れていない *)
                      Fun.flip (es u).fold () @@ fun (v, c, e) () ->
                        let dv' = let open W in w + c in
                        match VArray.find d v with
                        | (dv, _) when W.compare dv dv' < 0 -> ()
                        | (dv, pv) when W.compare dv dv' = 0 ->
                            (* 新しい最短経路を見つけたので追加 *)
                            let pv' = P.union pv (P.snoc pu e) in
                            if pv != pv' then VArray.update d v (dv, pv')
                        | _ | exception Not_found ->
                            VArray.update d v (dv', P.snoc pu e);
                            q := WMap.update dv' (fun vs -> Some (v :: Option.value ~default:[] vs)) !q);
                min_binding_opt := WMap.min_binding_opt !q;
                dijkstra_aux t in
      (fun v -> fst @@ dijkstra_aux v),
      (fun v -> snd @@ dijkstra_aux v)
  end

  module ByArray = struct
    module Make (W : sig include Weight val inf : t end) (P : sig include Path val empty : t end) = struct
      type 'a church_list = { fold : 'b. ('a -> 'b -> 'b) -> 'b -> 'b }

      module WMap = Map.Make (W)

      let dijkstra n es s =
        let d = Array.make n W.inf in
        let r = Array.make n P.empty in
        let q = ref (WMap.singleton W.zero [s]) in
        (* 既に最短距離が確定した辺へのクエリを高速化するため，
           ヒープの最小要素をメモしておく *)
        let min_binding_opt = ref (Some (W.zero, [s])) in
        r.(s) <- P.nil;
        d.(s) <- W.zero;
        let dijkstra_aux w us =
          q := WMap.remove w !q;
          List.iter (fun u ->
            if 0 <= W.compare d.(u) w then
              (* 未だ頂点uを訪れていない *)
              Fun.flip (es u).fold () @@ fun (v, c, e) () ->
                let dv' = let open W in w + c in
                match W.compare d.(v) dv' with
                | x when x < 0 -> ()
                (* 新しい最短経路を見つけたので追加 *)
                | 0 -> r.(v) <- P.union r.(v) (P.snoc r.(u) e)
                | _ ->
                    d.(v) <- dv';
                    r.(v) <- P.snoc r.(u) e;
                    q := WMap.update dv' (fun vs -> Some (v :: Option.value ~default:[] vs)) !q) us;
          min_binding_opt := WMap.min_binding_opt !q in
        let rec distance t =
          match !min_binding_opt with
          (* もう既に全ての頂点までの距離が分かっている *)
          | None -> d.(t)
          | Some (w, us) ->
              if W.compare d.(t) w <= 0
              (* 既に終点までの距離が分かっているので返す *)
              then d.(t)
              (* 終点までの距離が分かっていないので，ダイクストラ法を続行 *)
              else (dijkstra_aux w us; distance t) in
        let rec path t =
          match !min_binding_opt with
          (* もう既に全ての頂点までの最短経路が分かっている *)
          | None -> r.(t)
          | Some (w, us) ->
              if W.compare d.(t) w < 0
              (* 既に終点までの全ての最短経路が分かっているので返す *)
              then r.(t)
              (* 終点までの距離が分かっていないので，ダイクストラ法を続行 *)
              else (dijkstra_aux w us; path t) in
        distance, path

      let dijkstra_dense n es s =
        let d = Array.make n W.inf in
        let r = Array.make n P.empty in
        r.(s) <- P.nil;
        d.(s) <- W.zero;
        let rec dijkstra_dense_aux = function
          | [] -> ()
          | v :: vs ->
              let u, us = List.fold_left (fun (u, us) v ->
                if W.compare d.(u) d.(v) < 0
                then (u, v :: us)
                else (v, u :: us)) (v, []) vs in
              (es u).fold (fun (v, c, e) () ->
                let dv' = let open W in d.(u) + c in
                match W.compare d.(v) dv' with
                | x when x < 0 -> ()
                | 0 -> r.(v) <- P.union r.(v) (P.snoc r.(u) e)
                | _ -> d.(v) <- dv'; r.(v) <- P.snoc r.(u) e) ();
              dijkstra_dense_aux us in
        dijkstra_dense_aux (List.init n Fun.id);
        (Array.get d, Array.get r)
      end
  end

  module ByHashtbl = struct
    module Make (V : Hashtbl.HashedType) (W : Weight) (P : Path) = struct
      module VHash = Hashtbl.Make (V)
      module C = Core (W) (P) (struct
        type t = (W.t * P.t) VHash.t
        type vertex = V.t
        let find = VHash.find
        let update = VHash.replace
      end)
      include C

      let dijkstra n e s = C.dijkstra (VHash.create n) e s
    end
  end

  module ByMap = struct
    module Make (V : Map.OrderedType) (W : Weight) (P : Path) = struct
      module VMap = Map.Make (V)
      module C = Core (W) (P) (struct
        type t = (W.t * P.t) VMap.t ref
        type vertex = V.t
        let find d v = VMap.find v !d
        let update d v w = d := VMap.add v w !d
      end)
      include C

      let dijkstra e s = C.dijkstra (ref VMap.empty) e s
    end
  end
end

module IntWeightedDirectedGraphByArray = struct
  module Make
    (Path : sig
      type t
      type edge
      val nil : t
      val empty : t
      val snoc : t -> edge -> t
      val union : t -> t -> t
    end)
  = struct
    include (WeightedDirectedGraph.ByArray.Make (struct
      type t = int
      let zero = 0
      let inf = max_int
      let ( + ) = ( + )
      let compare = compare
    end) (Path))

    (* 辺の重さがごく小さい整数の場合は，Mapをキュー代わりに使うより配列を使った方が効率的
       時間計算量はO(E+VW)，空間計算量はO(E+W) *)
    let dijkstra_special :
      (* 頂点数n *)
      int ->
      (* 辺の重さの上限W *)
      int ->
      (* 頂点uを受け取って，
         uから伸びる辺の終点vと重さwの組みのリストを返す関数
         辺の重さwはW以下でなくてはならない *)
      (int -> (int * int * Path.edge) church_list) ->
      (* 始点 *)
      int ->
      (* 始点からの最短距離を返す関数と，始点からの最短経路を返す関数の組
         始点から辿り着けない場合，前者はinfを，後者はPath.emptyを返す
         これらの関数を覚えておけば，呼び出しごとの途中までの計算結果がシェアされる *)
      (int -> int) * (int -> Path.t)
    = fun n mw es s ->
      (* 各頂点への最短距離を格納するやつ *)
      let d = Array.make n max_int in
      (* 各頂点への最短経路を格納するやつ *)
      let r = Array.make n Path.nil in
      (* キュー *)
      let q = Array.make (mw + 1) [] in
      (* ヒープの最小要素の重み *)
      let w = ref 0 in
      (* ヒープの最小要素がどのインデックスに対応するか *)
      let i = ref 0 in
      (* ヒープに格納されている要素の数 *)
      let m = ref 1 in
      d.(s) <- 0;
      q.(0) <- [s];
      let rec dijkstra_aux t =
        (* 既に終点までの距離が分かっているので返す *)
        if !m <= 0 || d.(t) <= !w then (d.(t), r.(t)) else
        match q.(!i) with
        (* ヒープには重さがwの要素は無かった *)
        | [] ->
            incr w;
            incr i;
            if mw < !i then i := 0;
            dijkstra_aux t
        (* ヒープには重さwの要素uが存在する *)
        | u :: us ->
            (* ヒープから重さwの要素を削除する *)
            decr m;
            q.(!i) <- us;
            if !w <= d.(u) then
              (* 未だ頂点uを訪れていない *)
              (es u).fold (fun (v, c, e) () ->
                match compare d.(v) (!w + c) with
                | x when x < 0 -> ()
                | 0 -> r.(v) <- Path.union r.(v) (Path.snoc r.(u) e);
                | _ ->
                    d.(v) <- !w + c; (* 頂点vの重さを緩和 *)
                    r.(v) <- Path.snoc r.(u) e;
                    (* ヒープにvを追加する *)
                    let j = !i + c - if !i + c <= mw then 0 else mw + 1 in
                    q.(j) <- v :: q.(j);
                    incr m) ();
            dijkstra_aux t in
      (fun v -> fst @@ dijkstra_aux v),
      (fun v -> snd @@ dijkstra_aux v)
  end
end

module G = IntWeightedDirectedGraphByArray.Make
(struct
  type t = unit
  type edge = unit
  let nil = ()
  let empty = ()
  let snoc _ _ = ()
  let union = Fun.const
end)

let () = Scanf.scanf "%d %d %d\n" @@ fun n m s ->
  let es = Array.make n [] in
  for i = 0 to m - 1 do
    Scanf.scanf "%d %d %d %d\n" @@ fun u v a b ->
      es.(u - 1) <- (v - 1, a, b) :: es.(u - 1);
      es.(v - 1) <- (u - 1, a, b) :: es.(v - 1);
  done;
  let vs = Array.init n @@ fun _ -> Scanf.scanf "%d %d\n" @@ fun c d -> (c, d) in
  let f (v, w) = n * w + v in
  let finv x = (x mod n, x / n) in
  let d, _ = Fun.flip (G.dijkstra (n * 2501)) (f (0, min 2500 s)) @@ fun p ->
    { G.fold = fun g acc ->
      let (v, w) = finv p in
      g (let (c, d) = vs.(v) in (f (v, min 2500 (w + c)), d, ())) @@
      List.fold_right (fun (u, a, b) acc ->
        if w < a
        then acc
        else g (f (u, w - a), b, ()) acc) es.(v) acc } in
  for v = 1 to n - 1 do
    Printf.printf "%d\n" @@
    List.fold_left min max_int @@
    List.init 2501 @@ fun w -> d @@ f (v, w)
  done


module WeightedDirectedGraph
: sig
  (* 配列を用いたダイクストラ法の実装
     単純な速さでは一番だが，インターフェースが不便 *)
  module ByArray : sig
    module Make :
      functor
      (* 辺の重さ *)
      (Weight : sig
        type t
        val inf : t
        val zero : t
        val ( + ) : t -> t -> t
        val compare : t -> t -> int
      end)
      (* 道の集合の表現 *)
      (Path : sig
        type t
        (* 辺の名前 *)
        type edge
        (* 長さ0の道だけのsingleton *)
        val nil : t
        (* 空集合 *)
        val empty : t
        (* 与えられた集合に属する道について，それぞれ末尾に辺を付け足した集合 *)
        val snoc : t -> edge -> t
        (* 道の集合のunion
           最短経路は一つだけ分かればよい場合はFun.constを与えるとよい *)
        val union : t -> t -> t
      end) ->
        sig
          type 'a church_list = { fold : 'b. ('a -> 'b -> 'b) -> 'b -> 'b }

          (* 頂点を[0, n)の自然数に限定したグラフに対してのダイクストラ法
             時間計算量O(E log E)なので，疎なグラフなら速い *)
          val dijkstra :
          (* 頂点数n *)
          int ->
          (* 隣接リスト *)
          (int -> (int * Weight.t * Path.edge) church_list) ->
          (* 始点 *)
          int ->
          (* 始点からの最短距離を返す関数と，始点からの最短経路を返す関数の組
             始点から辿り着けない場合，前者はinfを，後者はPath.emptyを返す
             これらの関数を覚えておけば，呼び出しごとの途中までの計算結果がシェアされる *)
          (int -> Weight.t) * (int -> Path.t)

          (* 頂点を[0, n)の自然数に限定したグラフに対してのダイクストラ法
             時間計算量O(V^2)なので，密なグラフなら速い *)
          val dijkstra_dense :
          (* 頂点数n *)
          int ->
          (* 隣接リスト *)
          (int -> (int * Weight.t * Path.edge) church_list) ->
          (* 始点 *)
          int ->
          (* 始点からの最短距離を返す関数と，始点からの最短経路を返す関数の組
             始点から辿り着けない場合，前者はinfを，後者はPath.emptyを返す
             これらの関数を覚えておけば，呼び出しごとの途中までの計算結果がシェアされる *)
          (int -> Weight.t) * (int -> Path.t)
      end
  end

  (* ハッシュテーブルを用いたダイクストラ法の実装
     配列を用いた実装よりは扱いやすいインターフェースを持つ
     ハッシュ関数を上手く選べば配列を用いた実装より1.5倍遅い程度ですむ *)
  module ByHashtbl : sig
    module Make :
      functor
      (* 頂点 *)
      (Vertex : Hashtbl.HashedType)
      (* 辺の重さ *)
      (Weight : sig
        type t
        val inf : t
        val zero : t
        val ( + ) : t -> t -> t
        val compare : t -> t -> int
      end)
      (* 道の集合の表現 *)
      (Path : sig
        type t
        (* 辺の名前 *)
        type edge
        (* 長さ0の道だけのsingleton *)
        val nil : t
        (* 与えられた集合に属する道について，それぞれ末尾に辺を付け足した集合 *)
        val snoc : t -> edge -> t
        (* 道の集合のunion
           最短経路は一つだけ分かればよい場合はFun.constを与えるとよい *)
        val union : t -> t -> t
      end) ->
      sig
        type 'a church_list = { fold : 'b. ('a -> 'b -> 'b) -> 'b -> 'b }

        val dijkstra :
        (* 頂点数（Hashtbl.tを用いるので目安程度） *)
        int ->
        (* 隣接リスト *)
        (Vertex.t -> (Vertex.t * Weight.t * Path.edge) church_list) ->
        (* 始点 *)
        Vertex.t ->
        (* 始点からの最短距離を返す関数と，始点からの最短経路を返す関数の組
           両者とも始点から辿り着けなければNot_foundを投げる
           これらの関数を覚えておけば，呼び出しごとの途中までの計算結果がシェアされる *)
        (Vertex.t -> Weight.t) * (Vertex.t -> Path.t)
      end
  end

  (* Mapを用いたダイクストラ法の実装
     配列を用いた実装より4倍ぐらい遅いが，
     一番扱いやすいインターフェースを持ち，無限グラフにも対応可能 *)
  module ByMap : sig
    module Make :
      functor
      (* 頂点 *)
      (Vertex : Map.OrderedType)
      (* 辺の重み *)
      (Weight : sig
        type t
        val zero : t
        val ( + ) : t -> t -> t
        val compare : t -> t -> int
      end)
      (* 道の集合の表現 *)
      (Path : sig
        type t
        (* 辺の名前 *)
        type edge
        (* 長さ0の道だけのsingleton *)
        val nil : t
        (* 与えられた集合に属する道について，それぞれ末尾に辺を付け足した集合 *)
        val snoc : t -> edge -> t
        (* 道の集合のunion
           最短経路は一つだけ分かればよい場合はFun.constを与えるとよい *)
        val union : t -> t -> t
      end) ->
      sig
        type 'a church_list = { fold : 'b. ('a -> 'b -> 'b) -> 'b -> 'b }

        val dijkstra :
        (* 隣接リスト *)
        (Vertex.t -> (Vertex.t * Weight.t * Path.edge) church_list) ->
        (* 始点 *)
        Vertex.t ->
        (* 始点からの最短距離を返す関数と，始点からの最短経路を返す関数の組
           両者とも始点から辿り着けなければNot_foundを投げる
           これらの関数を覚えておけば，呼び出しごとの途中までの計算結果がシェアされる *)
        (Vertex.t -> Weight.t) * (Vertex.t -> Path.t)
      end
  end
end
= struct
  module type Weight = sig
    type t
    val zero : t
    val ( + ) : t -> t -> t
    val compare : t -> t -> int
  end

  module type Path = sig
    type t
    type edge
    val nil : t
    val snoc : t -> edge -> t
    val union : t -> t -> t
  end

  (* 最短距離を格納するデータ構造を抽象化したダイクストラ法の実装 *)
  module Core
    (W : Weight)
    (P : Path)
    (* グラフの頂点を添字とした配列 *)
    (VArray : sig
      type t
      type vertex (* グラフの頂点 *)
      val find : t -> vertex -> W.t * P.t (* 最短距離が格納されていなければNot_foundを投げる *)
      val update : t -> vertex -> W.t * P.t -> unit
    end) =
  struct
    type 'a church_list = { fold : 'b. ('a -> 'b -> 'b) -> 'b -> 'b }

    module WMap = Map.Make (W)

    let dijkstra d es s =
      VArray.update d s (W.zero, P.nil);
      let q = ref (WMap.singleton W.zero [s]) in
      (* 既に最短距離が確定した辺へのクエリを高速化するため，
         ヒープの最小要素をメモしておく *)
      let min_binding_opt = ref (Some (W.zero, [s])) in
      let rec dijkstra_aux t =
        match !min_binding_opt with
        (* もう既に全ての頂点までの距離が分かっている *)
        | None -> VArray.find d t
        | Some (w, us) ->
            match VArray.find d t with
            (* 既に終点までの距離が分かっているので返す *)
            | (x, _) as ans when W.compare x w <= 0 -> ans
            (* 終点までの距離が分かっていないので，ダイクストラ法を続行 *)
            | _ | exception Not_found ->
                q := WMap.remove w !q;
                Fun.flip List.iter us (fun u ->
                  match VArray.find d u with
                  | (d, _) when 0 < W.compare w d -> ()
                  | (_, pu) ->
                      (* 未だ頂点uを訪れていない *)
                      Fun.flip (es u).fold () @@ fun (v, c, e) () ->
                        let dv' = let open W in w + c in
                        match VArray.find d v with
                        | (dv, _) when W.compare dv dv' < 0 -> ()
                        | (dv, pv) when W.compare dv dv' = 0 ->
                            let pv' = P.union pv (P.snoc pu e) in
                            if pv != pv' then VArray.update d v (dv, pv')
                        | _ | exception Not_found ->
                            VArray.update d v (dv', P.snoc pu e);
                            q := WMap.update dv' (fun vs -> Some (v :: Option.value ~default:[] vs)) !q);
                min_binding_opt := WMap.min_binding_opt !q;
                dijkstra_aux t in
      (fun v -> fst @@ dijkstra_aux v),
      (fun v -> snd @@ dijkstra_aux v)
  end

  module ByArray = struct
    module Make (W : sig include Weight val inf : t end) (P : sig include Path val empty : t end) = struct
      module C = Core (W) (P) (struct
        type t = (W.t * P.t) array
        type vertex = int
        let find = Array.get
        let update = Array.set
      end)
      include C

      let dijkstra n e s = C.dijkstra (Array.make n (W.inf, P.empty)) e s

      let dijkstra_dense n es s =
        let d = Array.make n W.inf in
        let r = Array.make n P.empty in
        r.(s) <- P.nil;
        d.(s) <- W.zero;
        let rec dijkstra_dense_aux = function
          | [] -> ()
          | v :: vs ->
              let u, us = List.fold_left (fun (u, us) v ->
                if W.compare d.(u) d.(v) < 0
                then (u, v :: us)
                else (v, u :: us)) (v, []) vs in
              (es u).fold (fun (v, c, e) () ->
                let dv' = let open W in d.(u) + c in
                match W.compare d.(v) dv' with
                | -1 -> ()
                | 0 -> r.(v) <- P.union r.(v) (P.snoc r.(u) e)
                | 1 -> d.(v) <- dv'; r.(v) <- P.snoc r.(u) e) ();
              dijkstra_dense_aux us in
        dijkstra_dense_aux (List.init n Fun.id);
        (Array.get d, Array.get r)
      end
  end

  module ByHashtbl = struct
    module Make (V : Hashtbl.HashedType) (W : Weight) (P : Path) = struct
      module VHash = Hashtbl.Make (V)
      module C = Core (W) (P) (struct
        type t = (W.t * P.t) VHash.t
        type vertex = V.t
        let find = VHash.find
        let update = VHash.replace
      end)
      include C

      let dijkstra n e s = C.dijkstra (VHash.create n) e s
    end
  end

  module ByMap = struct
    module Make (V : Map.OrderedType) (W : Weight) (P : Path) = struct
      module VMap = Map.Make (V)
      module C = Core (W) (P) (struct
        type t = (W.t * P.t) VMap.t ref
        type vertex = V.t
        let find d v = VMap.find v !d
        let update d v w = d := VMap.add v w !d
      end)
      include C

      let dijkstra e s = C.dijkstra (ref VMap.empty) e s
    end
  end
end

module IntWeightedDirectedGraphByArray = struct
  module Make
    (Path : sig
      type t
      type edge
      val nil : t
      val empty : t
      val snoc : t -> edge -> t
      val union : t -> t -> t
    end)
  = struct
    include (WeightedDirectedGraph.ByArray.Make (struct
      type t = int
      let zero = 0
      let inf = max_int
      let ( + ) = ( + )
      let compare = compare
    end) (Path))

    (* 辺の重さがごく小さい整数の場合は，Mapをキュー代わりに使うより配列を使った方が効率的
       時間計算量はO(E+VW)，空間計算量はO(E+W) *)
    let dijkstra_special :
      (* 頂点数n *)
      int ->
      (* 辺の重さの上限W *)
      int ->
      (* 頂点uを受け取って，
         uから伸びる辺の終点vと重さwの組みのリストを返す関数
         辺の重さwはW以下でなくてはならない *)
      (int -> (int * int * Path.edge) church_list) ->
      (* 始点 *)
      int ->
      (* 始点からの最短距離を返す関数と，始点からの最短経路を返す関数の組
         始点から辿り着けない場合，前者はinfを，後者はPath.emptyを返す
         これらの関数を覚えておけば，呼び出しごとの途中までの計算結果がシェアされる *)
      (int -> int) * (int -> Path.t)
    = fun n mw es s ->
      (* 各頂点への最短距離を格納するやつ *)
      let d = Array.make n max_int in
      (* 各頂点への最短経路を格納するやつ *)
      let r = Array.make n Path.nil in
      (* キュー *)
      let q = Array.make (mw + 1) [] in
      (* ヒープの最小要素の重み *)
      let w = ref 0 in
      (* ヒープの最小要素がどのインデックスに対応するか *)
      let i = ref 0 in
      (* ヒープに格納されている要素の数 *)
      let m = ref 1 in
      d.(s) <- 0;
      q.(0) <- [s];
      let rec dijkstra_aux t =
        (* 既に終点までの距離が分かっているので返す *)
        if !m <= 0 || d.(t) <= !w then (d.(t), r.(t)) else
        match q.(!i) with
        (* ヒープには重さがwの要素は無かった *)
        | [] ->
            incr w;
            incr i;
            if mw < !i then i := 0;
            dijkstra_aux t
        (* ヒープには重さwの要素uが存在する *)
        | u :: us ->
            (* ヒープから重さwの要素を削除する *)
            decr m;
            q.(!i) <- us;
            if !w <= d.(u) then
              (* 未だ頂点uを訪れていない *)
              (es u).fold (fun (v, c, e) () ->
                match compare d.(v) (!w + c) with
                | -1 -> ()
                | 0 -> r.(v) <- Path.union r.(v) (Path.snoc r.(u) e);
                | 1 ->
                    d.(v) <- !w + c; (* 頂点vの重さを緩和 *)
                    r.(v) <- Path.snoc r.(u) e;
                    (* ヒープにvを追加する *)
                    let j = !i + c - if !i + c <= mw then 0 else mw + 1 in
                    q.(j) <- v :: q.(j);
                    incr m) ();
            dijkstra_aux t in
      (fun v -> fst @@ dijkstra_aux v),
      (fun v -> snd @@ dijkstra_aux v)
  end
end

module G = IntWeightedDirectedGraphByArray.Make
(struct
  type t = unit
  type edge = unit
  let nil = ()
  let empty = ()
  let snoc _ _ = ()
  let union = Fun.const
end)

let () = Scanf.scanf "%d %d %d\n" @@ fun n m s ->
  let es = Array.make n [] in
  for i = 0 to m - 1 do
    Scanf.scanf "%d %d %d %d\n" @@ fun u v a b ->
      es.(u - 1) <- (v - 1, a, b) :: es.(u - 1);
      es.(v - 1) <- (u - 1, a, b) :: es.(v - 1);
  done;
  let vs = Array.init n @@ fun _ -> Scanf.scanf "%d %d\n" @@ fun c d -> (c, d) in
  let f (v, w) = n * w + v in
  let finv x = (x mod n, x / n) in
  let d, _ = Fun.flip (G.dijkstra (n * 2501)) (f (0, min 2500 s)) @@ fun p ->
    { G.fold = fun g acc ->
      let (v, w) = finv p in
      g (let (c, d) = vs.(v) in (f (v, min 2500 (w + c)), d, ())) @@
      List.fold_right (fun (u, a, b) acc ->
        if w < a
        then acc
        else g (f (u, w - a), b, ()) acc) es.(v) acc } in
  for v = 1 to n - 1 do
    Printf.printf "%d\n" @@
    List.fold_left min max_int @@
    List.init 2501 @@ fun w -> d @@ f (v, w)
  done