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 * 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 * 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 * 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 * 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
      dijkstra_aux
  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);
        fun v -> (d.(v), r.(v))
      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 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 fst @@ 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の道 *)
        val nil : t
        (* 道の後ろに辺を付け足した道 *)
        val snoc : t -> edge -> 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.nil)を返す
             この関数を覚えておけば，呼び出しごとの途中までの計算結果がシェアされる *)
          (int -> Weight.t * Path.t)

          (* 頂点を[0, n)の自然数に限定したグラフに対してのダイクストラ法
             時間計算量O(V^2)なので，密なグラフなら速い *)
          val dijkstra_dense :
          (* 頂点数n *)
          int ->
          (* 隣接リスト *)
          (int -> (int * Weight.t * Path.edge) church_list) ->
          (* 始点 *)
          int ->
          (* 始点からの最短距離と，その経路を返す関数
             始点から辿り着けなければ(inf, Path.nil)を返す
             この関数を覚えておけば，呼び出しごとの途中までの計算結果がシェアされる *)
          (int -> Weight.t * 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の道 *)
        val nil : t
        (* 道の後ろに辺を付け足した道 *)
        val snoc : t -> edge -> 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 * 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の道 *)
        val nil : t
        (* 道の後ろに辺を付け足した道 *)
        val snoc : t -> edge -> 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 * 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
  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 -> ()
                  | (_, p) ->
                      (* 未だ頂点uを訪れていない *)
                      Fun.flip (es u).fold () @@ fun (v, c, e) () ->
                        let open W in
                        match VArray.find d v with
                        | (d, _) when W.compare d (w + c) <= 0 -> ()
                        | _ | exception Not_found ->
                            VArray.update d v (w + c, P.snoc p e);
                            q := WMap.add (w + c) (v :: try WMap.find (w + c) !q with Not_found -> []) !q);
                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) (P : Path) = 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.nil)) e s

      let dijkstra_dense n es s =
        let d = Array.make n W.inf in
        let r = Array.make n P.nil 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
              (es u).fold (fun (v, c, e) () ->
                let open W in
                if 0 < W.compare d.(v) (d.(u) + c) then
                  (d.(v) <- d.(u) + c; r.(v) <- P.snoc r.(u) e)) ();
              dijkstra_dense_aux us in
        dijkstra_dense_aux (List.init n Fun.id);
        fun v -> (d.(v), r.(v))
      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
      (* 長さ0の道 *)
      val nil : t
      (* 道の後ろに辺を付け足した道 *)
      val snoc : t -> edge -> 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.nil)を返す
         この関数を覚えておけば，呼び出しごとの途中までの計算結果がシェアされる *)
      (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) () ->
                if !w + c < d.(v) then begin
                  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
                end) ();
            dijkstra_aux t in
      dijkstra_aux
  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 _ _ = ()
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 fst @@ d (v, w) with Not_found -> max_int
  done

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
: 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の道 *)
        val nil : t
        (* 道の後ろに辺を付け足した道 *)
        val snoc : t -> edge -> 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.nil)を返す
             この関数を覚えておけば，呼び出しごとの途中までの計算結果がシェアされる *)
          (int -> Weight.t * Path.t)

          (* 頂点を[0, n)の自然数に限定したグラフに対してのダイクストラ法
             時間計算量O(V^2)なので，密なグラフなら速い *)
          val dijkstra_dense :
          (* 頂点数n *)
          int ->
          (* 隣接リスト *)
          (int -> (int * Weight.t * Path.edge) church_list) ->
          (* 始点 *)
          int ->
          (* 始点からの最短距離と，その経路を返す関数
             始点から辿り着けなければ(inf, Path.nil)を返す
             この関数を覚えておけば，呼び出しごとの途中までの計算結果がシェアされる *)
          (int -> Weight.t * 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の道 *)
        val nil : t
        (* 道の後ろに辺を付け足した道 *)
        val snoc : t -> edge -> 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 * 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の道 *)
        val nil : t
        (* 道の後ろに辺を付け足した道 *)
        val snoc : t -> edge -> 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 * 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
  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 -> ()
                  | (_, p) ->
                      (* 未だ頂点uを訪れていない *)
                      Fun.flip (es u).fold () @@ fun (v, c, e) () ->
                        let open W in
                        match VArray.find d v with
                        | (d, _) when W.compare d (w + c) <= 0 -> ()
                        | _ | exception Not_found ->
                            VArray.update d v (w + c, P.snoc p e);
                            q := WMap.update (w + c) (fun vs -> Some (v :: Option.value ~default:[] vs)) !q);
                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) (P : Path) = 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.nil)) e s

      let dijkstra_dense n es s =
        let d = Array.make n W.inf in
        let r = Array.make n P.nil 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
              (es u).fold (fun (v, c, e) () ->
                let open W in
                if 0 < W.compare d.(v) (d.(u) + c) then
                  (d.(v) <- d.(u) + c; r.(v) <- P.snoc r.(u) e)) ();
              dijkstra_dense_aux us in
        dijkstra_dense_aux (List.init n Fun.id);
        fun v -> (d.(v), r.(v))
      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
      (* 長さ0の道 *)
      val nil : t
      (* 道の後ろに辺を付け足した道 *)
      val snoc : t -> edge -> 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.nil)を返す
         この関数を覚えておけば，呼び出しごとの途中までの計算結果がシェアされる *)
      (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) () ->
                if !w + c < d.(v) then begin
                  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
                end) ();
            dijkstra_aux t in
      dijkstra_aux
  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 _ _ = ()
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 fst @@ 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の道 *)
        val nil : t
        (* 道の後ろに辺を付け足した道 *)
        val snoc : t -> edge -> 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.nil)を返す
             この関数を覚えておけば，呼び出しごとの途中までの計算結果がシェアされる *)
          (int -> Weight.t * Path.t)

          (* 頂点を[0, n)の自然数に限定したグラフに対してのダイクストラ法
             時間計算量O(V^2)なので，密なグラフなら速い *)
          val dijkstra_dense :
          (* 頂点数n *)
          int ->
          (* 隣接リスト *)
          (int -> (int * Weight.t * Path.edge) church_list) ->
          (* 始点 *)
          int ->
          (* 始点からの最短距離と，その経路を返す関数
             始点から辿り着けなければ(inf, Path.nil)を返す
             この関数を覚えておけば，呼び出しごとの途中までの計算結果がシェアされる *)
          (int -> Weight.t * 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の道 *)
        val nil : t
        (* 道の後ろに辺を付け足した道 *)
        val snoc : t -> edge -> 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 * 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の道 *)
        val nil : t
        (* 道の後ろに辺を付け足した道 *)
        val snoc : t -> edge -> 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 * 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
  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 -> ()
                  | (_, p) ->
                      (* 未だ頂点uを訪れていない *)
                      Fun.flip (es u).fold () @@ fun (v, c, e) () ->
                        let open W in
                        match VArray.find d v with
                        | (d, _) when W.compare d (w + c) <= 0 -> ()
                        | _ | exception Not_found ->
                            VArray.update d v (w + c, P.snoc p e);
                            q := WMap.update (w + c) (fun vs -> Some (v :: Option.value ~default:[] vs)) !q);
                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) (P : Path) = 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.nil)) e s

      let dijkstra_dense n es s =
        let d = Array.make n W.inf in
        let r = Array.make n P.nil 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
              (es u).fold (fun (v, c, e) () ->
                let open W in
                if 0 < W.compare d.(v) (d.(u) + c) then
                  (d.(v) <- d.(u) + c; r.(v) <- P.snoc r.(u) e)) ();
              dijkstra_dense_aux us in
        dijkstra_dense_aux (List.init n Fun.id);
        fun v -> (d.(v), r.(v))
      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 WMap = Map.Make (W)

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

      let dijkstra es s =
        let q = ref (WMap.singleton W.zero [s]) in
        let d = ref (VMap.singleton s (W.zero, P.nil)) in
        (* 既に最短距離が確定した辺へのクエリを高速化するため，
           ヒープの最小要素をメモしておく *)
        let min_binding_opt = ref (Some (W.zero, [s])) in
        let rec dijkstra_aux t =
          match !min_binding_opt with
          (* もう既に全ての頂点までの距離が分かっている *)
          | None -> VMap.find t !d
          | Some (w, us) ->
              match VMap.find t !d 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 VMap.find u !d with
                    | (d, _) when 0 < W.compare w d -> ()
                    | (_, p) ->
                        (* 未だ頂点uを訪れていない *)
                        Fun.flip (es u).fold () @@ fun (v, c, e) () ->
                          let open W in
                          d := Fun.flip (VMap.update v) !d @@ function
                            | Some (d, _) as o when W.compare d (w + c) <= 0 -> o
                            | _ ->
                                q := WMap.update (w + c) (fun vs -> Some (v :: Option.value ~default:[] vs)) !q;
                                Some (w + c, P.snoc p e));
                  min_binding_opt := WMap.min_binding_opt !q;
                  dijkstra_aux t in
        dijkstra_aux
    end
  end
end
module IntWeightedDirectedGraphByArray = struct
  module Make
    (Path : sig
      type t
      (* 辺の名前 *)
      type edge
      (* 長さ0の道 *)
      val nil : t
      (* 道の後ろに辺を付け足した道 *)
      val snoc : t -> edge -> 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.nil)を返す
         この関数を覚えておけば，呼び出しごとの途中までの計算結果がシェアされる *)
      (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) () ->
                if !w + c < d.(v) then begin
                  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
                end) ();
            dijkstra_aux t in
      dijkstra_aux
  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 _ _ = ()
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 fst @@ 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の道 *)
        val nil : t
        (* 道の後ろに辺を付け足した道 *)
        val snoc : t -> edge -> 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.nil)を返す
             この関数を覚えておけば，呼び出しごとの途中までの計算結果がシェアされる *)
          (int -> Weight.t * Path.t)

          (* 頂点を[0, n)の自然数に限定したグラフに対してのダイクストラ法
             時間計算量O(V^2)なので，密なグラフなら速い *)
          val dijkstra_dense :
          (* 頂点数n *)
          int ->
          (* 隣接リスト *)
          (int -> (int * Weight.t * Path.edge) church_list) ->
          (* 始点 *)
          int ->
          (* 始点からの最短距離と，その経路を返す関数
             始点から辿り着けなければ(inf, Path.nil)を返す
             この関数を覚えておけば，呼び出しごとの途中までの計算結果がシェアされる *)
          (int -> Weight.t * 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の道 *)
        val nil : t
        (* 道の後ろに辺を付け足した道 *)
        val snoc : t -> edge -> 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 * 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の道 *)
        val nil : t
        (* 道の後ろに辺を付け足した道 *)
        val snoc : t -> edge -> 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 * 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
  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 -> ()
                  | (_, p) ->
                      (* 未だ頂点uを訪れていない *)
                      Fun.flip (es u).fold () @@ fun (v, c, e) () ->
                        let open W in
                        match VArray.find d v with
                        | (d, _) when W.compare d (w + c) <= 0 -> ()
                        | _ | exception Not_found ->
                            VArray.update d v (w + c, P.snoc p e);
                            q := WMap.update (w + c) (fun vs -> Some (v :: Option.value ~default:[] vs)) !q);
                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) (P : Path) = 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.nil)) e s

      let dijkstra_dense n es s =
        let d = Array.make n W.inf in
        let r = Array.make n P.nil 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
              (es u).fold (fun (v, c, e) () ->
                let open W in
                if 0 < W.compare d.(v) (d.(u) + c) then
                  (d.(v) <- d.(u) + c; r.(v) <- P.snoc r.(u) e)) ();
              dijkstra_dense_aux us in
        dijkstra_dense_aux (List.init n Fun.id);
        fun v -> (d.(v), r.(v))
      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
      (* 長さ0の道 *)
      val nil : t
      (* 道の後ろに辺を付け足した道 *)
      val snoc : t -> edge -> 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.nil)を返す
         この関数を覚えておけば，呼び出しごとの途中までの計算結果がシェアされる *)
      (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) () ->
                if !w + c < d.(v) then begin
                  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
                end) ();
            dijkstra_aux t in
      dijkstra_aux
  end
end

module G = IntWeightedDirectedGraphByArray.Make
(struct
  type t = unit
  type edge = unit
  let nil = ()
  let snoc _ _ = ()
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 -> fst @@ 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) ->
      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.ByArray.Make
(struct
  type t = int
  let zero = 0
  let inf = max_int
  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 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 -> Option.value ~default:max_int @@ 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) ->
      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


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.ByMap.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 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


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, VArray.find_opt d t with
        (* もう既に全ての頂点までの距離が分かっている *)
        | None, ans -> ans
        (* 既に終点までの距離が分かっているので返す *)
        | Some (w, _), (Some x as ans) when W.compare x w <= 0 -> ans
        (* 終点までの距離が分かっていないので，ダイクストラ法を続行 *)
        | Some (w, us), _ ->
            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.ByMap.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 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


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

        (* 頂点を[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 ->
        (* 始点から辿り着けなければNot_foundを投げる関数
           この関数を覚えておけば，呼び出しごとの途中までの計算結果がシェアされる *)
        (Vertex.t -> Weight.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) ->
      sig
        type 'a church_list = { fold : 'b. ('a -> 'b -> 'b) -> 'b -> 'b }

        val dijkstra :
        (* 隣接リスト *)
        (Vertex.t -> (Vertex.t * Weight.t) church_list) ->
        (* 始点 *)
        Vertex.t ->
        (* 始点から辿り着けなければNot_foundを投げる関数
           この関数を覚えておけば，呼び出しごとの途中までの計算結果がシェアされる *)
        (Vertex.t -> Weight.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 Core
    (W : Weight)
    (* グラフの頂点を添字とした配列 *)
    (VArray : sig
      type t
      type vertex (* グラフの頂点 *)
      val find : t -> vertex -> W.t (* 最短距離が格納されていなければNot_foundを投げる *)
      val update : t -> vertex -> W.t -> 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 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 d t
        | Some (w, us) ->
            match VArray.find d t with
            (* 既に終点までの距離が分かっているので返す *)
            | x when W.compare x w <= 0 -> x
            (* 終点までの距離が分かっていないので，ダイクストラ法を続行 *)
            | _ | exception Not_found ->
                q := WMap.remove w !q;
                Fun.flip List.iter us (fun u ->
                  if 0 <= W.compare (VArray.find d u) w then
                    (* 未だ頂点uを訪れていない *)
                    Fun.flip (e u).fold () @@ fun (v, c) () ->
                      let open W in
                      match VArray.find d v with
                      | d when W.compare d (w + c) <= 0 -> ()
                      | _ | exception Not_found ->
                          VArray.update d v (w + c);
                          q := WMap.update (w + c) (fun vs -> Some (v :: Option.value ~default:[] vs)) !q);
                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 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) 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 = 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) = struct
      module VMap = Map.Make (V)
      module C = Core (W) (struct
        type t = W.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 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)

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 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 ->
      try d (v, w) with Not_found -> max_int
  done