use std::str::FromStr;
use std::io::*;
use utils::*;

pub fn main() {
    let i = stdin();
    let mut o = Vec::new();
    run(i.lock(), &mut o);
    stdout().write_all(&o).unwrap();
}

fn run<R: BufRead, W: Write>(i: R, o: &mut W) {
    let mut i = AtRead::from(i);
    let n = i.read::<usize>();
    let mut reds = Vec::new();
    let mut blues = Vec::new();

    for _ in 0..n {
        reds.push(i.read2::<usize, usize>());
    }
    for _ in 0..n {
        blues.push(i.read2::<usize, usize>());
    }
    writeln!(o, "{}", solve(n, reds, blues)).unwrap();
}
fn solve(n: usize, mut reds: Vec<(usize, usize)>, mut blues: Vec<(usize, usize)>) -> usize {
    fn can_pair(r: (usize, usize), b: (usize, usize)) -> bool {
        r.0 < b.0 && r.1 < b.1
    };

    blues.sort();
    for &b in &blues {
        if let Some(i) = reds.iter()
            .enumerate()
            .filter(|&(_, &xy)| can_pair(xy, b))
            .max_by_key(|&(_, &(_, y))| y)
            .map(|(i, _)| i)
        {
            reds.remove(i);
        }
    }
    n - reds.len()
}

fn solve_old(n: usize, reds: Vec<(usize, usize)>, blues: Vec<(usize, usize)>) -> usize {
    /*
solveの代わりにsolve_oldを使用してもACするが、間違っている。
次の入力で最適解が出ない。

10
15 5
6 3
4 19
13 15
7 13
17 1
8 12
5 18
12 0
3 8
16 16
1 10
14 9
0 7
10 17
11 14
18 2
19 4
2 11
9 6
    */
    let can_pair = |n_red: usize, n_blue: usize| {
        let red = reds[n_red];
        let blue = blues[n_blue];
        red.0 < blue.0 && red.1 < blue.1
    };
    let mut cp_red = vec![0usize; n];
    let mut cp_blue = vec![0usize; n];

    for n_red in 0..n {
        for n_blue in 0..n {
            if can_pair(n_red, n_blue) {
                cp_red[n_red] += 1;
                cp_blue[n_blue] += 1;
            }
        }
    }
    let mut r = 0;
    loop {
        let min_red = cp_red
            .iter()
            .cloned()
            .enumerate()
            .filter(|&x| x.1 != 0)
            .min_by_key(|&x| x.1);
        let min_blue = cp_blue
            .iter()
            .cloned()
            .enumerate()
            .filter(|&x| x.1 != 0)
            .min_by_key(|&x| x.1);
        if let (Some((mut n_red, c_red)), Some((mut n_blue, c_blue))) = (min_red, min_blue) {
            if c_red < c_blue {
                n_blue = (0..n)
                    .filter(|&n_blue| can_pair(n_red, n_blue) && cp_blue[n_blue] != 0)
                    .min_by_key(|&n_blue| cp_blue[n_blue])
                    .unwrap();
            } else {
                n_red = (0..n)
                    .filter(|&n_red| can_pair(n_red, n_blue) && cp_red[n_red] != 0)
                    .min_by_key(|&n_red| cp_red[n_red])
                    .unwrap();
            }

            r += 1;
            for n_red in 0..n {
                if can_pair(n_red, n_blue) && cp_red[n_red] != 0 {
                    cp_red[n_red] -= 1;
                }
            }
            for n_blue in 0..n {
                if can_pair(n_red, n_blue) && cp_blue[n_blue] != 0 {
                    cp_blue[n_blue] -= 1;
                }
            }
            cp_red[n_red] = 0;
            cp_blue[n_blue] = 0;
        } else {
            break;
        }
    }
    r
}

mod utils {
    use super::*;
    use std::ops::*;

    pub struct AtRead<R: BufRead> {
        r: R,
        s: String,
    }

    macro_rules! fn_read {
        {$f:ident($($v:ident: $t:ident),*)} => {
            pub fn $f<$($t: FromStr),*>(&mut self) -> ($($t),*) {
                let i = &mut self.read_line().split(' ');
                $(
                    let $v = next(i);
                )*
                ($($v),*)
            }
        };
    }

    impl<R: BufRead> AtRead<R> {
        pub fn from(r: R) -> Self {
            AtRead {
                r: r,
                s: String::new(),
            }
        }
        pub fn read_line(&mut self) -> &str {
            self.s.clear();
            self.r.read_line(&mut self.s).unwrap();
            self.s.trim()
        }

        pub fn read<T: FromStr>(&mut self) -> T {
            self.read_line().parse().ok().unwrap()
        }
        fn_read! { read2(v1: T1, v2: T2) }
    }

    fn next<'a, T: FromStr, I: std::iter::Iterator<Item = &'a str>>(i: &mut I) -> T {
        i.next().unwrap().parse().ok().unwrap()
    }
}


Measured memory_bytes: 4352