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


Measured memory_bytes: 23780