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) ->
      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) church_list) ->
        (* 始点 *)
        int ->
        (* 始点から辿り着けなければNoneを返す関数
           この関数を覚えておけば，呼び出しごとの途中までの計算結果がシェアされる *)
        (int -> Weight.t option)

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

  (* ハッシュテーブルを用いたダイクストラ法の実装
     配列を用いた実装よりは扱いやすいインターフェースを持つ
     ハッシュ関数を上手く選べば配列を用いた実装より1.5倍遅い程度ですむ *)
  module ByHashtbl : sig
    module Make :
      functor
      (* 頂点 *)
      (Vertex : Hashtbl.HashedType)
      (* 辺の重み *)
      (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 :
        (* 頂点数（Hashtbl.tを用いるので目安程度） *)
        int ->
        (* 隣接リスト *)
        (Vertex.t -> (Vertex.t * Weight.t) church_list) ->
        (* 始点 *)
        Vertex.t ->
        (* 始点から辿り着けなければNoneを返す関数
           この関数を覚えておけば，呼び出しごとの途中までの計算結果がシェアされる *)
        (Vertex.t -> Weight.t option)
      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) ->
      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
  end
end
= struct
  module type Weight = sig
    type t
    val zero : t
    val ( + ) : t -> t -> t
    val compare : t -> t -> int
  end

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

    module WMap = Map.Make (W)

    let dijkstra d e s =
      VArray.update d s (fun _ -> Some W.zero);
      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_opt d t
        | Some (w, us) ->
            match VArray.find_opt d t with
            (* 既に終点までの距離が分かっているので返す *)
            | Some x as ans when W.compare x w <= 0 -> ans
            (* 終点までの距離が分かっていないので，ダイクストラ法を続行 *)
            | _ ->
                q := WMap.remove w !q;
                Fun.flip List.iter us (fun u ->
                  if 0 <= W.compare (Option.get (VArray.find_opt d u)) w then
                    (* 未だ頂点uを訪れていない *)
                    Fun.flip (e u).fold () @@ fun (v, c) () ->
                      let open W in
                      VArray.update d v @@ function
                        | Some d as od when W.compare d (w + c) <= 0 -> od
                        | _ ->
                            q := WMap.update (w + c) (fun vs -> Some (v :: Option.value ~default:[] vs)) !q;
                            Some (w + c));
                min_binding_opt := WMap.min_binding_opt !q;
                dijkstra_aux t in
      dijkstra_aux
  end

  module ByArray = struct
    module Make (W : sig include Weight val inf : t end) = struct
      module C = Core (W) (struct
        type t = W.t option array
        type vertex = int
        let find_opt = Array.get
        let update d v f = d.(v) <- f d.(v)
      end)
      include C

      let dijkstra n e s = C.dijkstra (Array.make n None) e s

      let dijkstra_dense n e s =
        let d = Array.make n W.inf in
        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
              Fun.flip (e u).fold () (fun (v, c) () ->
                let open W in
                if 0 < W.compare d.(v) (d.(u) + c) then
                  d.(v) <- d.(u) + c);
              dijkstra_dense_aux us in
        dijkstra_dense_aux (List.init n Fun.id);
        Array.get d
      end
  end

  module ByHashtbl = struct
    module Make (V : Hashtbl.HashedType) (W : Weight) = struct
      module VHash = Hashtbl.Make (V)
      module C = Core (W) (struct
        type t = W.t VHash.t
        type vertex = V.t
        let find_opt = VHash.find_opt
        let update d v f =
          let opt = VHash.find_opt d v in
          match opt, f opt with
          | None, None -> ()
          | None, Some p -> VHash.add d v p
          | Some _, None -> VHash.remove d v
          | Some p, Some p' -> if p != p' then VHash.replace d v p'
      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) = struct
      module VMap = Map.Make (V)
      module C = Core (W) (struct
        type t = W.t VMap.t ref
        type vertex = V.t
        let find_opt d v = VMap.find_opt v !d
        let update d v f = d := VMap.update v f !d
      end)
      include C

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

module G = WeightedDirectedGraph.ByHashtbl.Make
(struct
  type t = int * int
  let equal = ( = )
  let hash (v, w) = 2501 * v + w
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 (n * 2501)) (0, min 2500 s) @@ fun (v, w) ->
    { G.fold = fun f acc ->
      f (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 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 -> Option.value ~default:max_int @@ d (v, w)
  done


Measured memory_bytes: 30788