module DirectedGraph
  (* 道の表現 *)
  (Path : sig
    type t
    (* 辺の名前 *)
    type edge
    (* 長さ0の道 *)
    val nil : t
    (* 道の後ろに辺を付け足した道 *)
    val snoc : t -> edge -> t
  end) :
sig
  (* BFSにより，重みのないグラフの最短経路を求める *)
  val bfs :
    (* 頂点数（Hashtblを用いるので目安程度） *)
    int ->
    (* 辺の名前が付いた隣接リスト *)
    ('v -> ('v * Path.edge) list) ->
    (* 始点 *)
    'v ->
    (* 最短経路を返す関数 辿り着けなければNoneを返す） *)
    ('v -> Path.t option)
end = struct
  let rec bfs_aux es d frontier t =
    try Some (Hashtbl.find d t) with
    | Not_found ->
        match !frontier with
        | [] -> None
        | _ :: _ ->
            frontier := List.fold_right (fun u ->
              List.fold_right (fun (v, e) frontier ->
                if Hashtbl.mem d v
                then frontier
                else (Hashtbl.add d v (Path.snoc (Hashtbl.find d u) e); v :: frontier))
              (es u)) !frontier [];
            bfs_aux es d frontier t

  (*
   * 終点に辿り着いた時点で探索を切り上げるが，
   * 戻り値の関数を覚えておくと，途中まで探索した結果が再利用される
   * （#trace bfs_aux すると分かりやすい）
   *)
  let bfs n es s =
    let d = Hashtbl.create n in
    Hashtbl.add d s Path.nil;
    let frontier = ref [s] in
    bfs_aux es d frontier
end

module FlowNetwork
  (* 流量 *)
  (Flow : sig
    type t
    val inf : t
    val zero : t
    val ( + ) : t -> t -> t
    val ( - ) : t -> t -> t
    val compare : t -> t -> int
  end) :
sig
  val max_flow :
    (* 頂点の数（Hashtblを用いるので目安程度） *)
    int ->
    (* 各辺の容量 逆辺を含める必要はない *)
    ('v * 'v * Flow.t) list ->
    (* 始点 *)
    'v ->
    (* 終点 *)
    'v ->
    (* 最大フロー *)
    Flow.t
end =
struct
  module G = DirectedGraph (struct
    type t = int
    type edge = unit
    let nil = 0
    let snoc t _ = t + 1
  end)

  (* 増加パスをDFSで探し，流せるだけ流していく *)
  let rec dfs capacity add_edge iter level v t f =
    if v = t then f
    else begin
      let rec loop () =
        match Hashtbl.find iter v with
        | exception Not_found -> Flow.zero
        | (u, i) ->
            Hashtbl.remove iter v;
            (* capacity i <= 0 *)
            if Flow.compare (capacity i) Flow.zero <= 0 || level u <= level v then loop ()
            else begin
              let d = dfs capacity add_edge iter level u t @@
                (* min f (capacity i) *)
                if Flow.compare f (capacity i) <= 0 then f else capacity i in
              (* d <= 0 *)
              if Flow.compare d Flow.zero <= 0 then loop ()
              else (add_edge i d; d)
            end in
      loop ()
    end

  let max_flow n es s t =
    assert (s <> t);
    (* 各辺に流せる流量 *)
    let capacity = Array.make (2 * List.length es) Flow.zero in
    (* 逆辺を張りつつ，隣接リスト形式に変換 *)
    let adj = Hashtbl.create (2 * List.length es) in
    List.iteri (fun i (u, v, c) ->
      (* 各辺は番号で管理する *)
      Hashtbl.add adj u (v, 2 * i);
      (* 容量はcapacityを見てほしい *)
      capacity.(2 * i) <- c;
      (* 逆辺 *)
      Hashtbl.add adj v (u, 2 * i + 1);
      capacity.(2 * i + 1) <- Flow.zero) es;
    (* 番号iの辺にcだけフローを流す *)
    let add_edge i c =
      let open Flow in
      capacity.(i) <- capacity.(i) - c;
      (* 逆辺 *)
      capacity.(i lxor 1) <- capacity.(i lxor 1) + c in
    let rec loop flow =
      let level = G.bfs n (fun v ->
        List.map (fun (u, _) -> (u, ())) @@
        List.filter (fun (_, i) ->
          (* 0 < capacity.(i) *)
          Flow.compare Flow.zero capacity.(i) < 0) @@
          Hashtbl.find_all adj v) s in
      if level t = None then flow
      else
        let iter = Hashtbl.copy adj in
        let rec inner flow =
          let f = dfs (fun i -> capacity.(i)) add_edge iter level s t Flow.inf in
          if Flow.compare f Flow.zero <= 0 then flow
          else inner (Flow.( + ) flow f) in
        loop @@ inner flow in
    loop Flow.zero
end

module G = FlowNetwork (struct
  include Pervasives
  type t = int
  let zero = 0
  let inf = max_int
end)

let () = Scanf.scanf "%d\n" @@ fun n ->
  let abs = Array.init n @@ fun _ ->
    Scanf.scanf "%d %d\n" @@ fun a b -> a, b in
  let cds = Array.init n @@ fun _ ->
    Scanf.scanf "%d %d\n" @@ fun c d -> c, d in
  Printf.printf "%d\n" @@ G.max_flow (2 * n + 1) (
    Array.to_list (Array.init n (fun i -> (`Source, `Red i, 1))) @
    Array.to_list (Array.init n (fun i -> (`Blue i, `Sink, 1))) @
    List.concat @@ Array.to_list @@ Array.mapi (fun i (a, b) ->
      List.concat @@ Array.to_list @@ Array.mapi (fun j (c, d) ->
        if a < c && b < d then [(`Red i, `Blue j, 1)]
        else []) cds) abs) `Source `Sink


Measured memory_bytes: 5632