On a two-dimensional plane, there are N red points and N blue points.
The coordinates of the i-th red point are (a_i, b_i), and the coordinates of the i-th blue point are (c_i, d_i).
A red point and a blue point can form a friendly pair when, the x-coordinate of the red point is smaller than that of the blue point, and the y-coordinate of the red point is also smaller than that of the blue point.
At most how many friendly pairs can you form? Note that a point cannot belong to multiple pairs.

-----Constraints-----
 - All input values are integers.
 - 1 \leq N \leq 100
 - 0 \leq a_i, b_i, c_i, d_i < 2N
 - a_1, a_2, ..., a_N, c_1, c_2, ..., c_N are all different.
 - b_1, b_2, ..., b_N, d_1, d_2, ..., d_N are all different.

-----Input-----
Input is given from Standard Input in the following format:
N
a_1 b_1
a_2 b_2
:
a_N b_N
c_1 d_1
c_2 d_2
:
c_N d_N

-----Output-----
Print the maximum number of friendly pairs.

-----Sample Input-----
3
2 0
3 1
1 3
4 2
0 4
5 5

-----Sample Output-----
2

For example, you can pair (2, 0) and (4, 2), then (3, 1) and (5, 5).

Difficulty: introductory

Starter code:

Solutions:
N = int(input())
ab = [list(map(int, input().split())) for _ in range(N)]
cd = [list(map(int, input().split())) for _ in range(N)]
ab.sort()
cd.sort()

g = [[] for _ in range(N)]

for i, pab in enumerate(ab):
    for j, pcd in enumerate(cd):
        if pab[0] < pcd[0] and pab[1] < pcd[1]:
            g[j].append([pab[1],i])
        
ans = 0
s = set()

for gg in g:
    gg.sort(reverse=True)
    for ggg in gg:
        if ggg[1] in s:continue
        else:
            ans += 1
            s.add(ggg[1])
            break
print(ans)


N = int(input())
R = [list(map(int,input().split())) for n in range(N)]
B = [list(map(int,input().split())) for n in range(N)]
R.sort(key=lambda x:-x[1])
B.sort()
ans=0

for c,d in B:
  for a,b in R:
    if a<c and b<d:
      ans+=1
      R.remove([a,b])
      break

print(ans)

import sys
import heapq, math
from itertools import zip_longest, permutations, combinations, combinations_with_replacement
from itertools import accumulate, dropwhile, takewhile, groupby
from functools import lru_cache
from copy import deepcopy

sys.setrecursionlimit(10000000)

N = int(input())
AB = []
CD = []

for i in range(N):
    A, B = map(int, input().split())
    AB.append((A, B))

for i in range(N):
    C, D = map(int, input().split())
    CD.append((C, D))

AB.sort()
CD.sort()

used = [False] * N
cnt = 0

for i in range(N):
    m = -1
    for j in range(N):
        if not used[j] and CD[i][0] > AB[j][0] and CD[i][1] > AB[j][1]:
            if m < 0 or AB[m][1] < AB[j][1]:
                m = j

    if m >= 0:
        used[m] = True
        cnt += 1

print(cnt)

import sys
input = sys.stdin.readline

from scipy.sparse import csr_matrix
from scipy.sparse.csgraph import maximum_bipartite_matching
import numpy as np

N = int(input())

X = []
Y = []
for i in range(N):
    X.append([int(i) for i in input().split()])

for i in range(N):
    Y.append([int(i) for i in input().split()])

data = []
for i in range(len(X)):
    for j in range(N):
        if X[i][0] < Y[j][0] and X[i][1] < Y[j][1]:
            data.append([i,j,1])


if not data:
    print(0)
    return

edge = np.array(data, dtype = np.int64).T
# graph = csr_matrix((edge[2], (edge[:2] - 1)), (V, V))
graph = csr_matrix((edge[2], (edge[:2])), (len(X), len(Y)))           # 番号のデクリメントが不要な場合

matching = maximum_bipartite_matching(graph, perm_type="column")

print(sum(d!=-1 for d in matching))

N=int(input())
red=[]
blue=[]
for _ in range(N):
  a,b = map(int,input().split())
  red.append((a+1,b+1))
for _ in range(N):
  c,d = map(int,input().split())
  blue.append((c+1,d+1))

blue.sort(key=lambda x:x[0])
for b in blue:
  c = None
  bx, by = b
  for r in red:
    rx, ry = r
    if rx < bx and ry < by:
      if c is None or c[1] < ry:
        c = r
  if c:
    red.remove(c)

print(N-len(red))

# coding: utf-8
import sys

sr = lambda: sys.stdin.readline().rstrip()
ir = lambda: int(sr())
lr = lambda: list(map(int, sr().split()))

"""
Nが小さいので、Y座標でcandに入れておく
"""
N = ir()
AB = [lr() for _ in range(N)]
CD = [lr() for _ in range(N)]
cand = [0] * (2*N)
ABCD = [(a, b, 0) for a, b in AB] + [(c, d, 1) for c, d in CD]
ABCD.sort()
answer = 0
for X, Y, Z in ABCD:
    if Z == 0:
        cand[Y] += 1
    else:
        for y in range(Y-1, -1, -1):
            if cand[y] > 0:
                answer += 1
                cand[y] -= 1
                break

print(answer)


N = int(input())
ab = [list(map(int, input().split())) for _ in range(N)]
cd = [list(map(int, input().split())) for _ in range(N)]
ab.sort(reverse=True)
cd.sort()
p = 0
for c in cd:
    ac = [-1, -1]
    for a in ab:
        if c[0] > a[0] and c[1] > a[1] and ac[1] < a[1]:
            ac = a
    if ac != [-1, -1]:
        p += 1
        ab.remove(ac)

print(p)


n = int(input())
AB = list(list(map(int,input().split())) for _ in range(n))
CD = list(list(map(int,input().split())) for _ in range(n))

CD.sort() # sort x in ascending order
AB.sort(key=lambda z: z[1], reverse=True) # sort x in descending order

dim_b = [[] for _ in range(n)]
for b in range(n):
    for r in range(n):
        if AB[r][0] < CD[b][0] and AB[r][1] < CD[b][1]:
            dim_b[b] += [r]

vis_r = [False]*(n)
for b in range(n): # ascending order of x
    for r in dim_b[b]: # descending order of y
        if not vis_r[r]: vis_r[r] = True; break

print((sum(vis_r)))


#!/usr/bin/env python3

import networkx as nx


n = int(input())
ab = [list(map(int, input().split())) for i in range(n)]
cd = [list(map(int, input().split())) for i in range(n)]


match_list = [[] for i in range(n)]
for i in range(n):
    for j in range(n):
        a, b = ab[i]
        c, d = cd[j]

        if a < c and b < d:
            match_list[i].append(j)
# print(match_list)


group1 = list(range(n))
group2 = list(range(n, 2*n))

g = nx.Graph()
g.add_nodes_from(group1, bipartite=1)
g.add_nodes_from(group2, bipartite=0)

for i, list_ in enumerate(match_list):
    for j in list_:
        g.add_edge(i, j+n, weight=1)

# A, B = bipartite.sets(g)
# print(A, B)
# pos = dict()
# pos.update((n, (1, i)) for i, n in enumerate(A))
# pos.update((n, (2, i)) for i, n in enumerate(B))
# nx.draw_networkx(g, pos)
# nx.draw_networkx_edges(g, pos)
# plt.axis("off")
# plt.show()


d = nx.max_weight_matching(g)

print((len(d)))


n=int(input())
ab=[list(map(int,input().split())) for _ in range(n)]
cd=[list(map(int,input().split())) for _ in range(n)]
ab.sort(key=lambda x:x[0])
cd.sort(key=lambda x:x[0])
ans=0
i=0
red_x=[]
import bisect
for c,d in cd:
  while i<n and ab[i][0]<c:
    bisect.insort_right(red_x,ab[i][1])
    i+=1
  if red_x and red_x[0]<d:
    idx=bisect.bisect_right(red_x,d)-1
    ans+=1
    red_x.pop(idx)
print(ans)

from collections import defaultdict
from itertools import product

N = int(input())

red_points = [tuple(map(int, input().split(' '))) for _ in range(N)]
blue_points = [tuple(map(int, input().split(' '))) for _ in range(N)]

edges = defaultdict(set)

for i, j in product(list(range(N)), repeat=2):
    a, b = red_points[i]
    c, d = blue_points[j]

    if a < c and b < d:
        edges[i].add(j + N)
        edges[j + N].add(i)

pairs = [-1] * (2 * N)
ans = 0


def dfs(v, seen):
    seen[v] = True
    for u in edges[v]:
        w = pairs[u]
        if w < 0 or (not seen[w] and dfs(w, seen)):
            pairs[v] = u
            pairs[u] = v
            return True
    return False


for v in range(2 * N):
    if pairs[v] < 0:
        seen = [False] * (2 * N)
        if dfs(v, seen):
            ans += 1

print(ans)


N = int(input())
Red = [[int(T) for T in input().split()] for TN in range(0,N)]
Red.sort(key=lambda X:X[1],reverse=True)
Blue = [[int(T) for T in input().split()] for TN in range(0,N)]
Blue.sort(key=lambda X:X[0])
Count = 0

for TB in range(0,N):
    DelInd = -1
    for TR in range(0,len(Red)):
        if Blue[TB][0]>Red[TR][0] and Blue[TB][1]>Red[TR][1]:
            DelInd = TR
            break
    if DelInd!=-1:
        del Red[DelInd]
        Count += 1
print(Count)

N = int(input())#100
AB = [0] * N
for i in range(N):
  AB[i] = list(map(int, input().split()))
AB = sorted(AB)
CD = [0] * N
for i in range(N):
  CD[i] = list(map(int, input().split()))
CD = sorted(CD)
#print(AB, CD)

ans = 0

used = [0] * N
for i in range(N):
  now_x, now_y = CD[i][0], CD[i][1]
  max_y = -1
  nn = -1
  for j in range(N):
    if (now_x > AB[j][0]) and (used[j] == 0):
      if now_y > AB[j][1]:
        if max_y < AB[j][1]:
          max_y = AB[j][1]
          nn = j
  if max_y != -1:
    ans += 1
    used[nn] = 1
    
print(ans)    
    
    
  
  
  
  
  


def main():
    from sys import stdin
    def input():
        return stdin.readline().strip()
    
    n = int(input())
    red = [tuple(map(int, input().split())) for _ in range(n)]
    blue = [tuple(map(int, input().split())) for _ in range(n)]

    red.sort()
    blue.sort()

    now = 0
    for i in blue:
        while now < len(red) and red[now] < i:
            now += 1
        
        l = red[:now]
        if l == []:
            continue

        l = sorted(l, key=lambda x: x[1])
        if l[0][1] > i[1]:
            continue
        
        # binary search
        left = 0
        right = len(l) - 1
        while left < right:
            center = (left + right + 1) // 2
            if l[center][1] < i[1]:
                left = center
            else:
                right = center - 1

        red.remove(l[left])
        now -= 1

    print(n - len(red))

main()

n = int(input())
ab = []
for i in range(n):
    ab.append(list(map(int, input().split())))
cd = []
for i in range(n):
    cd.append(list(map(int, input().split())))
cd.sort()
ab.sort(key = lambda x: x[1], reverse = True)
flag_ab = [False for i in range(n)]
count = 0
for i in range(n):
    c, d = cd[i][0], cd[i][1]
    for j in range(n):
        if flag_ab[j] == True:
            continue
        a, b = ab[j][0], ab[j][1]
        if c > a and d > b:
            flag_ab[j] = True
            count += 1
            break
print(count)

import networkx as nx
N = int(input())
AB = [[int(_) for _ in input().split()] for _ in range(N)]
CD = [[int(_) for _ in input().split()] for _ in range(N)]
G = nx.DiGraph()
for a, b in AB:
    G.add_edge(-1, a * 1000 + b, capacity=1)
for c, d in CD:
    G.add_edge(c * 1000 + d, -2, capacity=1)
for a, b in AB:
    for c, d in CD:
        if a < c and b < d:
            G.add_edge(a * 1000 + b, c * 1000 + d, capacity=1)
flow_value, flow_dict = nx.maximum_flow(G, -1, -2)
print(flow_value)


N = int(input())
ab = [tuple(map(int, input().split())) for _ in range(N)]
cd = [tuple(map(int, input().split())) for _ in range(N)]

ab.sort(key=lambda xy: xy[1], reverse=True)
cd.sort()

ans = 0
for c, d in cd:
    for index, (a, b) in enumerate(ab):
        if a < c and b < d:
            ab[index] = (201, 201)
            ans += 1
            break

print(ans)


from heapq import heapify, heappush, heappop
N = int(input())
A = []
for i in range(N):
    A.append(tuple(map(int, input().split())))
A.sort()

B = []
for i in range(N):
    B.append(tuple(map(int, input().split())))
B.sort()

heap = []
heapify(heap)
aindex = count = 0
for b in B:
    while aindex < len(A) and A[aindex][0] < b[0]:
        heappush(heap, -A[aindex][1])
        aindex += 1
    buf = []
    while heap and b[1] <= -heap[0]:
        ay = heappop(heap)
        buf.append(ay)
    if heap and -heap[0] < b[1]:
        count += 1
        heappop(heap)
    for ay_ in buf:
        heappush(heap, ay_)
print(count)

import collections, itertools, copy


class MaximumFlow:
    def ford_fulkerson(self, G, s, t):
        G_residue = copy.deepcopy(G)

        def dfs(start, used):
            if start == t:
                return [start]
            for end, cap in list(G_residue[start].items()):
                if cap > 0 and end not in used:
                    used.add(end)
                    ret = dfs(end, used)
                    if ret:
                        return ret + [start]
            return []

        flow_value = 0
        while True:
            root = dfs(s, set([s]))
            if root:
                root = root[::-1]
                residue = min(
                    [G_residue[a][b] for a, b in zip(root, root[1:])])
                flow_value += residue
                for a, b in zip(root, root[1:]):
                    G_residue[a][b] -= residue
                    G_residue[b][a] += residue
            else:
                return (flow_value, G_residue)


N = int(input())
AB = [[int(_) for _ in input().split()] for _ in range(N)]
CD = [[int(_) for _ in input().split()] for _ in range(N)]
G = collections.defaultdict(lambda: collections.defaultdict(int))
for a, b in AB:
    G[-1][1000 * a + b] = 1
for c, d in CD:
    G[1000 * c + d][-2] = 1
for ab, cd in itertools.product(AB, CD):
    a, b = ab
    c, d = cd
    if a < c and b < d:
        G[1000 * a + b][1000 * c + d] = 1
flow_value, flow_dict = MaximumFlow().ford_fulkerson(G, -1, -2)
print(flow_value)


n, *ABCD = map(int, open(0).read().split())
AB = sorted([(a, b) for a, b in zip(ABCD[:2*n:2], ABCD[1:2*n:2])], key=lambda x:-x[1])
CD = sorted([(c, d) for c, d in zip(ABCD[2*n::2], ABCD[2*n+1::2])])

for c, d in CD:
    for i in range(len(AB)):
        a, b = AB[i]
        if a < c and b < d:
            _ = AB.pop(i)
            break
print(n-len(AB))

N=int(input())
AB=sorted([list(map(int, input().split())) for _ in range(N)])
CD=sorted([list(map(int, input().split())) for _ in range(N)])

paira=-1
pairb=-1
ans=0

for i in range(N):
	tempcd=CD[i]
	for h in range(len(AB)):
		tempab=AB[h]
		if tempab[0]<tempcd[0] and tempab[1]<tempcd[1]:
			if pairb<tempab[1]:
				paira=tempab[0]
				pairb=tempab[1]
				pairnum=h
	if paira!=-1 and pairb!=-1:
		ans+=1
		AB.pop(pairnum)
		paira=-1
		pairb=-1

print(ans)
			


def resolve():
    '''
    code here
    '''
    import collections
    N = int(input())
    reds = [[int(item) for item in input().split()] for _ in range(N)]
    blues = [[int(item) for item in input().split()] for _ in range(N)]

    reds = sorted(reds, key=lambda x:x[1], reverse=True)
    blues.sort()

    que = collections.deque(blues)
    cnt = 0

    while que:

        bx, by = que.popleft()

        for rx, ry in reds[:]:
            if rx <= bx and ry <= by:
                cnt += 1
                reds.remove([rx, ry])
                break
    print(cnt)


def __starting_point():
    resolve()



__starting_point()

import sys
INF = 1 << 60
MOD = 10**9 + 7 # 998244353
sys.setrecursionlimit(2147483647)
input = lambda:sys.stdin.readline().rstrip()
from scipy.sparse import csr_matrix
from scipy.sparse.csgraph import maximum_bipartite_matching
def resolve():
    n = int(input())
    A = [tuple(map(int, input().split())) for _ in range(n)]
    B = [tuple(map(int, input().split())) for _ in range(n)]

    graph = csr_matrix([[int(A[i][0] < B[j][0] and A[i][1] < B[j][1]) for j in range(n)] for i in range(n)])
    ans = 0
    for a in maximum_bipartite_matching(graph):
        if a != -1:
            ans += 1
    print(ans)
resolve()

n = int(input())
cr = [tuple(map(int, input().split())) for _ in range(n)]
cb = [tuple(map(int, input().split())) for _ in range(n)]

cb.sort(key=lambda xy: xy[0])
cr.sort(key=lambda xy: xy[1], reverse=True)

npair = 0
for (bx, by) in cb:
    for (rx, ry) in cr:
        if rx < bx and ry < by:
            npair += 1
            cr.remove((rx, ry))
            break

print(npair)





N= int(input())
red=[list(map(int,input().split())) for i in range(N)]
red.sort()
blue=[list(map(int,input().split())) for i in range(N)]
blue.sort()
ans=0
from operator import itemgetter
for i in range(N):
   x,y=blue[i]
   l=[]
   for j in range(N):
      try:
         if x>red[j][0] and y>red[j][1]:
            l.append(red[j])
      except IndexError:
         break
   try:
      l.sort(key=itemgetter(1),reverse=True)
      red.remove(l[0])
   except IndexError:
      pass
print(N-len(red))

n=int(input())
red=[list(map(int,input().split())) for _ in range(n)]
blue=[list(map(int,input().split())) for _ in range(n)]
red.sort()
blue.sort()
 
p=0
for bb in blue:
  lis=[-1,-1]
  for rr in red:
    if rr[0]<bb[0] and rr[1]<bb[1] and lis[1]<rr[1]:
      lis=rr
  if lis!=[-1,-1]:
    red.remove(lis)
    p+=1
print(p)

import sys
input = sys.stdin.readline

class FordFulkerson:
    def __init__(self, n):
        self.N = n
        self.G = [[] for _ in range(n)]
        
    def add_edge(self, fr, to, cap):
        forward = [to, cap, None]
        forward[2] = backward = [fr, 0, forward]
        self.G[fr].append(forward)
        self.G[to].append(backward)
        
    def add_multi_edge(self, v1, v2, cap1, cap2):
        edge1 = [v2, cap1, None]
        edge1[2] = edge2 = [v1, cap2, edge1]
        self.G[v1].append(edge1)
        self.G[v2].append(edge2)
    
    def dfs(self, v, t, f):
        if v == t:
            return f
        used = self.used
        used[v] = 1
        for e in self.G[v]:
            w, cap, rev = e
            if cap and not used[w]:
                d = self.dfs(w, t, min(f, cap))
                if d:
                    e[1] -= d
                    rev[1] += d
                    return d
        return 0
    

    def flow(self, s, t):
        flow = 0
        f = INF = 10**9 + 7
        N = self.N
        while f:
            self.used = [0]*N
            f = self.dfs(s, t, INF)
            flow += f
        return flow
    
def main():
    n = int(input())
    red = [list(map(int, input().split())) for _ in range(n)]
    blue = [list(map(int, input().split())) for _ in range(n)]
    
    flow = FordFulkerson(n*2+2)
    for i in range(n):
        flow.add_edge(0, i+1, 1)
        flow.add_edge(n+i+1, 2*n+1, 1)
        for j in range(n):
            if red[i][0] < blue[j][0] and red[i][1] < blue[j][1]:
                flow.add_edge(i+1, n+j+1, 1)
    
    
    ans = flow.flow(0, 2*n+1)
    print(ans)
    
def __starting_point():
    main()

__starting_point()

n = int(input())
red  = [tuple(map(int, input().split())) for _ in range(n)]
blue = [tuple(map(int, input().split())) for _ in range(n)]
red.sort(key=lambda x:-x[1])
blue.sort()
count = 0
for xb, yb in blue:
    for i in range(n):
        if xb > red[i][0] and yb > red[i][1]:
            red[i] = (201, 201)
            count += 1
            break
print(count)


N = int(input())
Red = sorted([tuple(map(int, input().split())) for _ in range(N)])
Blue = sorted([tuple(map(int, input().split())) for _ in range(N)])

ans = 0
for bx,by in Blue:
    C = [(y,x) for x,y in Red if x<bx and y<by] #候補
    if len(C) == 0:
        continue
    ans += 1
    C.sort(reverse=True)
    Red.remove((C[0][1],C[0][0]))
print(ans)

import collections, itertools


class MaximumFlow:
    def __init__(self, G):
        self.G = G

    def ford_fulkerson(self, s, t):
        def dfs(start, used):
            G = self.G
            if start == t:
                return [start]
            for end, cap in list(G[start].items()):
                if cap > 0 and end not in used:
                    used.add(end)
                    ret = dfs(end, used)
                    if ret:
                        return ret + [start]
            return []

        fmax = 0
        cnt = 0
        while True:
            G = self.G
            cnt += 1
            root = dfs(s, set([s]))
            if root:
                root = root[::-1]
                residue = min([G[a][b] for a, b in zip(root, root[1:])])
                fmax += residue
                for a, b in zip(root, root[1:]):
                    G[a][b] -= residue
                    G[b][a] += residue
            else:
                return (fmax, G)


N = int(input())
AB = [[int(_) for _ in input().split()] for _ in range(N)]
CD = [[int(_) for _ in input().split()] for _ in range(N)]
G = collections.defaultdict(lambda: collections.defaultdict(int))
for a, b in AB:
    G[-1][1000 * a + b] = 1
for c, d in CD:
    G[1000 * c + d][-2] = 1
for ab, cd in itertools.product(AB, CD):
    a, b = ab
    c, d = cd
    if a < c and b < d:
        G[1000 * a + b][1000 * c + d] = 1
flow = MaximumFlow(G)
fmax, Gres = flow.ford_fulkerson(-1, -2)
print(fmax)


#
# abc091 c
#
import sys
from io import StringIO
import unittest
import bisect


class TestClass(unittest.TestCase):
    def assertIO(self, input, output):
        stdout, stdin = sys.stdout, sys.stdin
        sys.stdout, sys.stdin = StringIO(), StringIO(input)
        resolve()
        sys.stdout.seek(0)
        out = sys.stdout.read()[:-1]
        sys.stdout, sys.stdin = stdout, stdin
        self.assertEqual(out, output)

    def test_入力例_1(self):
        input = """3
2 0
3 1
1 3
4 2
0 4
5 5"""
        output = """2"""
        self.assertIO(input, output)

    def test_入力例_2(self):
        input = """3
0 0
1 1
5 2
2 3
3 4
4 5"""
        output = """2"""
        self.assertIO(input, output)

    def test_入力例_3(self):
        input = """2
2 2
3 3
0 0
1 1"""
        output = """0"""
        self.assertIO(input, output)

    def test_入力例_4(self):
        input = """5
0 0
7 3
2 2
4 8
1 6
8 5
6 9
5 4
9 1
3 7"""
        output = """5"""
        self.assertIO(input, output)

    def test_入力例_5(self):
        input = """5
0 0
1 1
5 5
6 6
7 7
2 2
3 3
4 4
8 8
9 9"""
        output = """4"""
        self.assertIO(input, output)


def resolve():
    N = int(input())
    AB = [list(map(int, input().split())) for _ in range(N)]
    CD = [list(map(int, input().split())) for _ in range(N)]

    AB.sort(reverse=True)
    CD.sort()

    ans = 0
    for ab in AB:
        a, b = ab
        ok = len(CD)
        ng = -1
        while abs(ok-ng) > 1:
            mid = (ok+ng)//2

            if CD[mid][0] >= a:
                ok = mid
            else:
                ng = mid

        if ok == len(CD):
            continue

        NCD = CD[ok:]
        NCD.sort(key=lambda x: x[1])
        ok = len(NCD)
        ng = -1
        while abs(ok-ng) > 1:
            mid = (ok+ng)//2

            if NCD[mid][1] >= b:
                ok = mid
            else:
                ng = mid

        if ok == len(NCD):
            continue
        else:
            ans += 1
            CD.remove(NCD[ok])

    print(ans)


def __starting_point():
    # unittest.main()
    resolve()

__starting_point()

n = int(input())
red  = [tuple(map(int, input().split())) for _ in range(n)]
blue = [tuple(map(int, input().split())) for _ in range(n)]

red.sort(key=lambda x:x[1])
blue.sort()

count = 0
for xb, yb in blue:
    max_y = -1
    max_i = -1
    for i in range(n):
        xr, yr = red[i]
        if xb > xr and yb > yr and max_y < yr:
            max_y, max_i = yr, i
    if max_y >= 0:
        red[max_i] = (201, 201)
        count += 1
print(count)




n=int(input())
R=sorted([list(map(int,input().split())) for i in range(n)], key=lambda R: -R[1])
B=sorted([list(map(int,input().split())) for i in range(n)])
ans=0
for c,d in B:
  for a,b in R:
    if a<c and b<d:
      R.remove([a,b]);ans+=1
      break
print(ans)

import collections, itertools, copy


class MaximumFlow:
    def ford_fulkerson(self, G, s, t):
        G_residue = copy.deepcopy(G)

        def dfs(start, used):
            if start == t:
                return [start]
            for end, cap in list(G_residue[start].items()):
                if cap > 0 and end not in used:
                    used.add(end)
                    ret = dfs(end, used)
                    if ret:
                        return ret + [start]
            return []

        flow_value = 0
        while True:
            root = dfs(s, set([s]))
            if root:
                root = root[::-1]
                residue = min(
                    [G_residue[a][b] for a, b in zip(root, root[1:])])
                flow_value += residue
                for a, b in zip(root, root[1:]):
                    G_residue[a][b] -= residue
                    G_residue[b][a] += residue
            else:
                return (flow_value, G_residue)


N = int(input())
AB = [[int(_) for _ in input().split()] for _ in range(N)]
CD = [[int(_) for _ in input().split()] for _ in range(N)]
G = collections.defaultdict(lambda: collections.defaultdict(int))
for a, b in AB:
    G[-1][1000 * a + b] = 1
for c, d in CD:
    G[1000 * c + d][-2] = 1
for ab, cd in itertools.product(AB, CD):
    a, b = ab
    c, d = cd
    if a < c and b < d:
        G[1000 * a + b][1000 * c + d] = 1
flow_value, G_residue = MaximumFlow().ford_fulkerson(G, -1, -2)
print(flow_value)
flow_dict = collections.defaultdict(lambda: collections.defaultdict(int))
for a in G:
    for b in G[a]:
        if G_residue[b][a] > 0:
            flow_dict[a][b] = G_residue[b][a]


n=int(input())
rs=[list(map(int,input().split())) for _ in range(n)]
bs=[list(map(int,input().split())) for _ in range(n)]
rs.sort(key=lambda x:x[1],reverse=True)
bs.sort()
ans=0
for c,d in bs:
    for a,b in rs:
        if a<c and b<d:
            ans+=1
            rs.remove([a,b])
            break
print(ans)


N = int(input())
R = [[0, 0] for _ in range(N)]
B = [[0, 0] for _ in range(N)]
Map = [['.' for __ in range(2*N)] for _ in range(2*N)]
for i in range(N):
  R[i][1], R[i][0] = map(int, input().split())
  Map[R[i][1]][R[i][0]] = 'R'
for i in range(N):
  B[i][0], B[i][1] = map(int, input().split())
  Map[B[i][0]][B[i][1]] = 'B'
R.sort(reverse=True)
B.sort()
RF = [True for _ in range(N)]
BF = [True for _ in range(N)]
cnt = 0
for i in range(N):
  for j in range(N):
    if BF[j] == True:
      if R[i][1] < B[j][0] and R[i][0] < B[j][1]:
        cnt += 1
        RF[i] = False
        BF[j] = False
        break
print(cnt)

n = int(input())
a = [list(map(int, input().split())) for _ in range(n)]
b = [list(map(int, input().split())) for _ in range(n)]
x = []
for i,j in a:
    x.append((i,j,1))
for i,j in b:
    x.append((i,j,2))
x.sort()
#print(x)
for i in range(2*n):
    x[i] = (x[i][1],x[i][2])
#print(x)
ans = 0
while len(x):
    maxindex = 0
    maxvalue = -1
    flag = 0
    for i in range(len(x)):
        if x[i][0]>maxvalue and x[i][1]==1:
            flag = 1
            maxvalue = x[i][0]
            maxindex = i
    if flag == 0:
        break
    #if (x[maxindex][1]==1):
        #x.pop(i)
    #else:
    #maxindex2 = 0
    #maxvalue2 = -1
    flag = 0
    for i in range(maxindex+1,len(x)):
        if (x[i][1]==2):
            if (x[i][0]>maxvalue):
                ans += 1
                x.pop(i)
                x.pop(maxindex)
                flag=1
                break
    if (flag==0):
        x.pop(maxindex)
print(ans)

n = int(input())
ab = [tuple(map(int, input().split())) for _ in range(n)]
cd = [tuple(map(int, input().split())) for _ in range(n)]
ab.sort(key=lambda x: (-x[1], x[0]))
cd.sort(key=lambda x: (x[0], x[1]))
s = [0] * n

for i in range(n):
    for j in range(n):
        if s[j] == 0 and ab[j][0] < cd[i][0] and ab[j][1] < cd[i][1]:
            s[j] = 1
            break
print((sum(s)))


def c_2d_plane_2n_points_bipartite_graph():
    import networkx as nx
    from networkx.algorithms.flow import dinitz
    N = int(input())
    Red_point_pos = [[int(i) for i in input().split()] for j in range(N)]
    Blue_point_pos = [[int(i) for i in input().split()] for j in range(N)]

    # 1 から N 番を赤い点に割り当て，N+1 番から 2N 番を青い点に割り当てる
    # ソースを 0 番とし，シンクを 2N+1 番とする
    graph = nx.DiGraph()
    graph.add_nodes_from(range(2 * N + 2))
    for i in range(N):
        for j in range(N):
            a, b = Red_point_pos[i]
            c, d = Blue_point_pos[j]
            if a < c and b < d:  # i 番の赤い点と j 番の青い点はペアにできうる
                graph.add_edge(i + 1, j + N + 1, capacity=1)
    for i in range(1, N + 1):
        graph.add_edge(0, i, capacity=1)
    for j in range(N + 1, 2 * N + 1):
        graph.add_edge(j, 2 * N + 1, capacity=1)
    return dinitz(graph, 0, 2 * N + 1).graph['flow_value']

print(c_2d_plane_2n_points_bipartite_graph())

import sys
mod=10**9+7 ; inf=float("inf")
from math import sqrt, ceil
from collections import deque, Counter, defaultdict #すべてのkeyが用意されてる defaultdict(int)で初期化
input=lambda: sys.stdin.readline().strip()
sys.setrecursionlimit(11451419)
from decimal import ROUND_HALF_UP,Decimal  #変換後の末尾桁を0や0.01で指定
  #Decimal((str(0.5)).quantize(Decimal('0'), rounding=ROUND_HALF_UP))
from functools import lru_cache
from bisect import bisect_left as bileft, bisect_right as biright
#メモ化再帰defの冒頭に毎回 @lru_cache(maxsize=10**10)
#引数にlistはだめ
#######ここまでテンプレ#######
#ソート、"a"+"b"、再帰ならPython3の方がいい
#######ここから天ぷら########
from collections import deque
class Dinic:
    def __init__(self, N):
        self.N= N
        self.G = [[] for i in range(N)]
    def add_edge(self,fr,to,cap=1): #つなぐノード2つ、容量
        forward=[to, cap, None]
        forward[2] = backward = [fr, 0, forward]
        self.G[fr].append(forward)
        self.G[to].append(backward)

    def add_multi_edge(self, v1, v2, cap1, cap2):
        edge1 = [v2, cap1, None]
        edge1[2] = edge2 = [v1, cap2, edge1]
        self.G[v1].append(edge1)
        self.G[v2].append(edge2)

    def bfs(self, s, t):
        self.level = level = [None]*self.N
        deq = deque([s])
        level[s] = 0
        G = self.G
        while deq:
            v = deq.popleft()
            lv = level[v] + 1
            for w, cap, _ in G[v]:
                if cap and level[w] is None:
                    level[w] = lv
                    deq.append(w)
        return level[t] is not None

    def dfs(self, v, t, f):
        if v == t:
            return f
        level = self.level
        for e in self.it[v]:
            w, cap, rev = e
            if cap and level[v] < level[w]:
                d = self.dfs(w, t, min(f, cap))
                if d:
                    e[1] -= d
                    rev[1] += d
                    return d
        return 0

    def flow(self, s, t):
        flow = 0
        INF = inf
        G = self.G
        while self.bfs(s, t):
            *self.it, = map(iter, self.G)
            f = INF
            while f:
                f = self.dfs(s, t, INF)
                flow += f
        return flow
n=int(input())
dinic=Dinic(2*n+2)


A=[] ; B=[]
for i in range(n):
    a,b=map(int,input().split())
    A.append([a,b])
for i in range(n):
    a,b=map(int,input().split())
    B.append([a,b])
for i in range(n):
    dinic.add_edge(2*n,i,1)
    dinic.add_edge(i+n, 2*n+1,1)
for i in range(n):
    for j in range(n):
        if A[i][0]<B[j][0] and A[i][1]<B[j][1]:
            dinic.add_edge(i,j+n)

print(dinic.flow(2*n,2*n+1))

from operator import itemgetter
N=int(input())
R=[list(map(int,input().split())) for n in range(N)]
B=[list(map(int,input().split())) for n in range(N)]
R.sort(key=itemgetter(1),reverse=True)
B.sort()
ans=0

for c,d in B :
    for a,b in R :
        if a<c and b<d :
            ans+=1
            R.remove([a,b])
            break

print(ans)

def abc091_c():
    n = int(input())
    red = []
    blue = []
    for _ in range(n):
        a, b = (int(x) for x in input().split())
        red.append((a, b))
    for _ in range(n):
        c, d = (int(x) for x in input().split())
        blue.append((c, d))
    blue = sorted(blue, key=lambda x: x[0])

    ans = 0
    r_used = [False]*n
    for c, d in blue:
        match = -1
        y_high = -1
        for i, (a, b) in enumerate(red):
            if r_used[i]: continue
            if not (a < c and b < d): continue
            if y_high < b:
                match = i
                y_high = b
        if match != -1:
            ans += 1
            r_used[match] = True
    print(ans)

def __starting_point():
    abc091_c()
__starting_point()

N = int(input())
red = [list(map(int, input().split())) for _ in range(N)]
blue = [list(map(int, input().split())) for _ in range(N)]
blue = sorted(blue, key=lambda x: x[0])

used = []
for i in range(N):
    c, d = blue[i]
    m, tmp = -1, -1
    for j in range(N):
        if j in used:
            continue
        a, b = red[j]
        if a < c and b < d:
            if b > m:
                m = b
                tmp = j
    if tmp != -1:
        used.append(tmp)
print((len(used)))


import sys
INF = 1 << 60
MOD = 10**9 + 7 # 998244353
sys.setrecursionlimit(2147483647)
input = lambda:sys.stdin.readline().rstrip()
import networkx as nx
def resolve():
    n = int(input())
    A = [tuple(map(int, input().split())) for _ in range(n)]
    B = [tuple(map(int, input().split())) for _ in range(n)]
    G = nx.Graph()
    G.add_nodes_from(range(n))
    G.add_nodes_from(range(n, 2 * n))
    for i in range(n):
        ax, ay = A[i]
        for j in range(n):
            bx, by = B[j]
            if ax < bx and ay < by:
                G.add_edge(i, n + j)

    A = nx.algorithms.bipartite.matching.hopcroft_karp_matching(G, top_nodes = range(n))
    print(len(A) // 2)
resolve()

import sys
def input(): return sys.stdin.readline().strip()
def mapint(): return map(int, input().split())
sys.setrecursionlimit(10**9)

from bisect import bisect_right
N = int(input())
ab = [list(mapint()) for _ in range(N)]
cd = [list(mapint()) for _ in range(N)]
ab.sort(reverse=True)
cd.sort(key=lambda x: x[1])
checked = [0]*N

ans = 0
for n in range(N):
    a, b = ab[n]
    for i in range(N):
        if checked[i]:
            continue
        c, d = cd[i]
        if a<c and b<d:
            ans += 1
            checked[i] = 1
            break

print(ans)

n = int(input())
ab=[]
for i in range(n):
    ab.append(list(map(int, input().split())))
ab = sorted(ab, key=lambda x:x[1], reverse=True)

cd=[]
for i in range(n):
    cd.append(list(map(int, input().split())))
cd = sorted(cd, key=lambda x:x[0])
# print(ab, flush=True)
# print(cd, flush=True)


ans = 0
for i in cd:
    for ji, j in enumerate(ab):
        if i[0]>j[0] and i[1]>j[1]:
            # print(i, j, flush=True)
            ans+=1
            ab.pop(ji)
            break;
print(ans, flush=True)



import operator
import bisect

n=int(input())
red=[tuple(map(int,input().split())) for _ in range(n)]
blue=[tuple(map(int,input().split())) for _ in range(n)]

red.sort(key=operator.itemgetter(0,1))
blue.sort(key=operator.itemgetter(0,1))
#print(red)
#print(blue)
count=0
for i in range(n):
  for j in reversed(list(range(len(red)))):
    #print("j",j)
    if not red:
      break
    if red[j][0]<blue[i][0]:
      tmp=red[:j+1]
      tmp.sort(key=lambda x:x[1],reverse=True)
      for t in tmp:
        if t[1]<blue[i][1]:
          count+=1
          red.pop(red.index(t))
          #print("t",t,"blue[i]",blue[i])
          break
    else:
      continue
    break

print(count)


import sys
sys.setrecursionlimit(10**8)
def ii(): return int(sys.stdin.readline())
def mi(): return map(int, sys.stdin.readline().split())
def li(): return list(map(int, sys.stdin.readline().split()))
def li2(N): return [list(map(int, sys.stdin.readline().split())) for _ in range(N)]
def dp2(ini, i, j): return [[ini]*i for _ in range(j)]
#import bisect #bisect.bisect_left(B, a)
#from collections import defaultdict #d = defaultdict(int) d[key] += value
#from collections import Counter # a = Counter(A).most_common()
#from itertools import accumulate #list(accumulate(A))

N = ii()
A = li2(N)
B = li2(N)

A = sorted(A, key=lambda x:x[1])
B = sorted(B, key=lambda x:x[0])

flag = [0] * N

for i in range(N):
    ind = -1
    for j in range(N):
        if A[j][1] < B[i][1]:
            ind = j
    while ind >= 0:
        if not flag[ind] and A[ind][0] < B[i][0]:
            flag[ind] = 1
            break
        ind -= 1

#print(flag)
print(sum(flag))

import bisect
N = int(input())
R = [tuple(map(int,input().split())) for i in range(N)]
B = [tuple(map(int,input().split())) for i in range(N)]

#ソートしてR<Bとなる点をGreedyで探索
R.sort()
B.sort()
i=0
ans=0
red_y = []
for b_x,b_y in B:
    #b_xよりxが小さいRをすべてred_yに追加
    while i<N and R[i][0]<b_x:
        bisect.insort_right(red_y,R[i][1])
        i+=1
    #r_x<b_x,r_y<b_yを満たす点があればカウント
    if red_y and red_y[0]<b_y:
        idx = bisect.bisect_right(red_y,b_y)-1
        ans+=1
        red_y.pop(idx)
print(ans)

n = int(input())
AB = list(list(map(int,input().split())) for _ in range(n))
CD = list(list(map(int,input().split())) for _ in range(n))

CD.sort() # sort x in ascending order
AB.sort(key=lambda z: z[1], reverse=True) # sort x in descending order

dim_b = [[] for _ in range(n)]
for b in range(n):
    bx, by = CD[b]
    for r in range(n):
        rx, ry = AB[r]
        if rx < bx and ry < by: dim_b[b] += [r]

vis_r = [False]*(n)
for b in range(n): # ascending order of x
    max_ry = max_r = -1
    for r in dim_b[b]: # descending order of y
        if vis_r[r]: continue
        rx, ry = AB[r]
        if max_ry < ry:
            max_ry = ry
            max_r = r
    if max_r >= 0: vis_r[max_r] = True
print((sum(vis_r)))


from collections import deque
N=int(input())
start = 0
end = 2*N+1

R = {}
B = {}
ad_matrix = [[0]*(2*N+2) for i in range(2*N+2)]
ad_dict = {}
ad_dict[start]=[]
ad_dict[end]=[]
for n in range(N):
    R[n+1] = (list(map(int,input().split())))
    ad_dict[n+1]=[]
    
for n in range(N):
    B[N+n+1] = (list(map(int,input().split())))
    ad_dict[N+n+1]=[]

# 隣接行列を作成(ad_matrix[start][end] = 1：接続)
for r_ in R.keys():
    ad_dict[start].append(r_)
    ad_dict[r_].append(start)
for b_ in B.keys():
    ad_dict[end].append(b_)
    ad_dict[b_].append(end)

for r_ in R.keys():
    ad_matrix[start][r_] = 1
    
    r = R[r_]
    for b_ in B.keys():
        ad_matrix[b_][end] = 1

        b = B[b_]
        
        if r[0] < b[0] and r[1] < b[1]:
            ad_matrix[r_][b_] = 1
            ad_dict[r_].append(b_)

ans = 0
while True:
    start = 0
    end = 2*N+1

    color = {}
    for n in range(end+1):
        color[n] = -1

    visit = deque([start])
    color[start] = 0

    while visit:
        start = visit[-1]
        for v in ad_dict[start]:
            if color[v] == -1:
                visit.append(v)
                color[v] = 0
                break
        else:
            visit.pop()
            color[start] = 1

#         print(visit,color)

        if color[end] == 0:
            #コストの更新
            visit = list(visit)
            flow = 10**10
            for d1,d2 in zip(visit[:-1],visit[1:]):
                flow = min(flow,ad_matrix[d1][d2])

            for d1,d2 in zip(visit[:-1],visit[1:]):
                ad_matrix[d1][d2] -= flow
                ad_matrix[d2][d1] += flow
                if ad_matrix[d1][d2] <= 0:
                    ad_dict[d1].remove(d2)
                    ad_dict[d2].append(d1)
            break
#     print(visit)
    if not visit:
        break
    ans += 1
print(ans)

n = int(input())
AB = list(list(map(int,input().split())) for _ in range(n))
CD = list(list(map(int,input().split())) for _ in range(n))

# print(*CD,sep='\n',end='\n---\n')
# print(*sorted(CD, key=lambda x: x[0]),sep='\n',end='\n---\n')
# CD.sort(key=lambda x: x[1])
# CD.sort(key=lambda x: x[0])
CD.sort()
# print(*CD,sep='\n',end='\n---\n')
# print(*AB,sep='\n',end='\n---\n')
AB.sort(key=lambda x: x[1], reverse=True)
# print(*AB,sep='\n',end='\n---\n')

dim_r = [[] for _ in range(n)]
dim_b = [[] for _ in range(n)]
# cnt_r = [0]*n
# cnt_b = [0]*n
for b in range(n):
    bx, by = CD[b]
    for r in range(n):
        rx, ry = AB[r]
        if rx < bx and ry < by:
            dim_r[r] += [b]
            dim_b[b] += [r]
            # cnt_b[b] += 1
            # cnt_r[r] += 1

# print(n)
# print(*AB,sep='\n',end='\n---\n')
# print(*CD,sep='\n',end='\n---\n')
# print(*dim_r,sep='\n',end='\n---\n')
# print(*dim_b,sep='\n',end='\n---\n')
# # print(cnt_b,end='\n---\n')

ans = 0

inf = 1000000000
vis_r = [False]*(n)
for b in range(n):
    bx, by = CD[b]
    # print('b,bx,by',b,bx,by)
    max_ry = -1
    max_r = -1
    for r in dim_b[b]:
        if vis_r[r]: continue
        # print('r,rx,ry',r,rx,ry)
        rx, ry = AB[r]
        if max_ry < ry:
            max_ry = ry
            max_r = r
    if max_r >= 0:
        # print('max_r,max_ry',max_r,max_ry)
        vis_r[max_r] = True
        ans += 1
    # print('---')
print(ans)


N=int(input())
a=[list(map(int,input().split())) for _ in range(N)]
c=[list(map(int,input().split())) for _ in range(N)]
X=[(q,w,0) for q,w in a]+[(e,r,1) for e,r in c]
X.sort()
ans=0
dp=[0]*(2*N)
for x,y,z in X:
  if z==0:
    dp[y]+=1
  else:
    for v in range(y-1,-1,-1):
      if dp[v]>0:
        ans+=1
        dp[v]-=1
        break
print(ans)

import sys
from collections import deque
input = sys.stdin.readline

class Dinic:
    def __init__(self, v):
        self.vertice = v
        self.inf = int(1e9)
        self.graph = [[] for i in range(v)]
        self.level = [0]*v
        self.iter = [0]*v
    
    def add_edge(self, fr, to, cap):
        self.graph[fr].append([to, cap, len(self.graph[to])])
        self.graph[to].append([fr, 0, len(self.graph[fr])-1])
    
    def bfs(self, s):
        self.level = [-1]*self.vertice
        que = deque([])
        self.level[s] = 0
        que.append(s)

        while que:
            v = que.popleft()
            for i in range(len(self.graph[v])):
                e = self.graph[v][i]
                if e[1] > 0 and self.level[e[0]] < 0:
                    self.level[e[0]] = self.level[v] + 1
                    que.append(e[0])
    
    def dfs(self, v, t, f):
        if v == t:
            return f
        for i in range(self.iter[v], len(self.graph[v])):
            self.iter[v] = i
            e = self.graph[v][i]
            if e[1] > 0 and self.level[v] < self.level[e[0]]:
                d = self.dfs(e[0], t, min(f, e[1]))
                if d > 0:
                    e[1] -= d
                    self.graph[e[0]][e[2]][1] += d
                    return d
        return 0
    
    def max_flow(self, s, t):
        flow = 0
        while True:
            self.bfs(s)
            if self.level[t] < 0:
                return flow
            self.iter = [0]*self.vertice

            f = self.dfs(s, t, self.inf)
            while f:
                flow += f
                f = self.dfs(s, t, self.inf)
    
def main():
    n = int(input())
    red = [list(map(int, input().split())) for _ in range(n)]
    blue = [list(map(int, input().split())) for _ in range(n)]
    
    flow = Dinic(n*2+2)
    for i in range(n):
        flow.add_edge(0, i+1, 1)
        flow.add_edge(n+i+1, 2*n+1, 1)
        for j in range(n):
            if red[i][0] < blue[j][0] and red[i][1] < blue[j][1]:
                flow.add_edge(i+1, n+j+1, 1)
    
    
    ans = flow.max_flow(0, 2*n+1)
    print(ans)
    
def __starting_point():
    main()
__starting_point()

N=int(input())
red=[]
blue=[]
for _ in range(N):
  a,b = map(int,input().split())
  red.append((a,b))
for _ in range(N):
  c,d = map(int,input().split())
  blue.append((c,d))

blue.sort(key=lambda x:x[0])
for bx, by in blue:
  c = None
  for rx, ry in red:
    if rx < bx and ry < by:
      if c is None or c[1] < ry:
        c = (rx, ry)
  if c:
    red.remove(c)

print(N-len(red))

def main():
    n = int(input())
    R, B = [], []
    for i in range(n):
        R.append(list(map(int, input().split())) + [0, i])
    for _ in range(n):
        B.append(list(map(int, input().split())))
    B.sort(key = lambda x: x[0])
    ans = 0
    for b in B:
        f = list([x for x in R if x[0] < b[0] and x[1] < b[1] and x[2] == 0])
        if len(f) != 0:
            f.sort(key = lambda x: x[1], reverse = True)
            p = f[0]
            ans += 1
            R[p[3]][2] = 1
    print(ans)        

def __starting_point():
    main()

__starting_point()

n = int(input())
ab = [list(map(int, input().split())) for _ in range(n)]
cd = [list(map(int, input().split())) for _ in range(n)]

g = [[0 for _ in range(2*n+2)] for _ in range(2*n+2)]

for (i, (a, b)) in enumerate(ab):
    fr = i+2
    g[0][fr] = 1
    for (j, (c, d)) in enumerate(cd):
        to = n+j+2
        g[to][1] = 1
        if a < c and b < d:
            g[fr][to] = 1

used = [False for _ in range(2 * n + 2)]
path = []
goal = 1
flow = [[0 for _ in range(2*n+2)] for _ in range(2*n+2)]


def bfs(v):
    used[v] = True
    for next in range(2 * n + 2):
        if g[v][next] == 0 or used[next]:
            pass
        elif next == goal:
            path.append(v)
            return True
        elif bfs(next):
            path.append(v)
            return True
    return False


ans = 0
while bfs(0):
    path.reverse()
    path.append(1)
    for i in range(len(path) - 1):
        g[path[i]][path[i + 1]] -= 1
        g[path[i + 1]][path[i]] += 1
    used = [False for _ in range(2 * n + 2)]
    path = []
    ans += 1
print(ans)


n=int(input())
red=[[] for i in range(n)]
blue=[[] for i in range(n)]
for i in range(n):
    a,b=list(map(int,input().split()))
    red[i].append(a)
    red[i].append(b)
for i in range(n):
    a,b=list(map(int,input().split()))
    blue[i].append(a)
    blue[i].append(b)
red=sorted(red)
blue=sorted(blue)
ans=0
for i in range(n):
    x=blue[i][0]
    y=blue[i][1]
    maxy=-1
    for j in range(n):
        if x>red[j][0] and y>red[j][1]:
            maxy=max(maxy,red[j][1])
    for j in range(n):
        if x>red[j][0] and maxy==red[j][1]:
            ans+=1
            red[j][0]=1000
            break
print(ans)


def resolve():
    import sys
    
    readline = sys.stdin.readline    # 1行だけ文字列にする

    N = int(readline())

    # 赤，青点をx,y座標の2次元リストとして入力
    red = [list(map(int, readline().split())) for _ in [0] * N]
    blue = [list(map(int, readline().split())) for _ in [0] * N]

    # 赤はy座標で降順ソート，青はx座標で昇順ソート
    red.sort(key=lambda x: x[1], reverse=True)
    blue.sort()

    ans = 0
    for c, d in blue:
        for a, b in red:
            if a <= c and b <= d:
                ans += 1
                red.remove([a, b])
                break
    print(ans)


resolve()


import networkx as nx

n = int(input())
graph = nx.DiGraph()
AB = [list(map(int, input().split())) for _ in range(n)]
CD = [list(map(int, input().split())) for _ in range(n)]

start = 10 ** 4
goal = 10 ** 4 + 1
for i in range(n):
    a, b = AB[i]
    graph.add_edge(start, i, weight=0, capacity=1)
    for j in range(n):
        c, d = CD[j]
        graph.add_edge(200 + j, goal, weight=0, capacity=1)
        if c > a and d > b:
            graph.add_edge(i, 200 + j, weight=0, capacity=1)

ans = nx.maximum_flow(graph, start, goal, capacity="capacity")
print((ans[0]))



n = int(input())
AB = list(list(map(int,input().split())) for _ in range(n))
CD = list(list(map(int,input().split())) for _ in range(n))

CD.sort() # sort x in ascending order
AB.sort(key=lambda z: z[1], reverse=True) # sort x in descending order

dim_b = [[] for _ in range(n)]
for b in range(n):
    for r in range(n):
        if AB[r][0] < CD[b][0] and AB[r][1] < CD[b][1]:
            dim_b[b] += [r]

vis_r = [False]*(n)
for b in range(n): # ascending order of x
    max_ry = max_r = -1
    for r in dim_b[b]: # descending order of y
        if vis_r[r]: continue
        if max_ry < AB[r][1]: max_ry = AB[r][1]; max_r = r
    if max_r >= 0: vis_r[max_r] = True
print((sum(vis_r)))


ma = lambda :map(int,input().split())
lma = lambda :list(map(int,input().split()))
tma = lambda :tuple(map(int,input().split()))
ni = lambda:int(input())
yn = lambda fl:print("YES") if fl else print("NO")
import collections
import math
import itertools
import heapq as hq
n = ni()
ab = []
for i in range(n):
    ab.append(lma())
ab.sort(key=lambda x:x[1],reverse=True)
ab.sort(reverse=True)
cd = []
for i in range(n):
    cd.append(lma())
cd.sort()
cd.sort(key=lambda x:x[1])
cnt=0
INF=10**9
for a,b in ab:
    #print("ab",a,b)
    for i in range(n):
        c,d = cd[i]
        if a<c and b<d:
            #print("cd",c,d)
            cnt+=1
            cd[i][0]=-INF
            cd[i][1]=-INF
            break
print(cnt)
#print(cd)


def c_2d_plane_2n_points_bipartite_graph():
    import networkx as nx
    from networkx.algorithms.flow import dinitz
    N = int(input())
    A, B, C, D = [], [], [], []
    for _ in range(N):
        a, b = [int(i) for i in input().split()]
        A.append(a)
        B.append(b)
    for _ in range(N):
        c, d = [int(i) for i in input().split()]
        C.append(c)
        D.append(d)

    # 赤い点の番号は 1~N とし，青い点の番号は N+1~2N とする
    # ソースを 0 番とし，シンクを 2N+1 番とする
    graph = nx.DiGraph()
    graph.add_nodes_from(range(2 * N + 2))
    for i in range(N):
        for j in range(N):
            if A[i] < C[j] and B[i] < D[j]:
                graph.add_edge(i + 1, j + N + 1, capacity=1)
    for i in range(1, N + 1):
        graph.add_edge(0, i, capacity=1)
    for j in range(N + 1, 2 * N + 1):
        graph.add_edge(j, 2 * N + 1, capacity=1)

    return dinitz(graph, 0, 2 * N + 1).graph['flow_value']

print(c_2d_plane_2n_points_bipartite_graph())

N = int(input())

reds = []
for i in range(N):
    a, b = list(map(int, input().split()))
    reds.append([a,b])
reds.sort(key=lambda x: x[1], reverse=True)

blues = []
for i in range(N):
    c, d = list(map(int, input().split()))
    blues.append([c,d])
blues.sort()

flag = [False for i in range(N)]
ans = 0
for i in range(N):
    c, d = blues[i][0], blues[i][1]
    for j in range(N):
        if flag[j] == True:
            continue
        a, b = reds[j][0], reds[j][1]
        if c>a and d>b:
            flag[j] = True
            ans += 1
            break
print(ans)


N = int(input())
ab = [[int(i) for i in input().split()] for _ in range(N)]
cd = [[int(i) for i in input().split()] for _ in range(N)]

ab.sort(key = lambda x: x[1], reverse=True)
cd.sort()

x = 0
for c, d in cd:
    for a, b in ab:
        if a < c and b < d:
            x += 1
            ab.remove([a, b])
            break

print(x)


def main():
    n = int(input())
    red = []
    red_used = [[False for _ in range(2 * n)] for _ in range(2 * n)]
    for _ in range(n):
        rp = list(map(int, input().split()))
        red.append(rp)
        red_used[rp[0]][rp[1]] = True
    ans = 0
    red.sort(key=lambda x: x[1], reverse=True)
    blue = [list(map(int, input().split())) for _ in range(n)]
    blue.sort(key=lambda x: x[0])
    for bx, by in blue:
        for rx, ry in red:
            if rx < bx and ry < by and red_used[rx][ry]:
                red_used[rx][ry] = False
                ans += 1
                break
    print(ans)


def __starting_point():
    main()

__starting_point()

n = int(input())
ab = []
cd = []
for i in range(n):
    ab.append(tuple(map(int,input().split())))

for g in range(n):
    cd.append(tuple(map(int,input().split())))

ab.sort(key=lambda x: x[1], reverse = True)
cd.sort()
used = [False]*n

ans = 0
for i in range(n):
    for g in range(n):
        if ab[i][0] < cd[g][0] and ab[i][1] < cd[g][1] and not used[g]:
            used[g] = True
            ans += 1
            break
print(ans)

n = int(input())
R = []
for i in range(n):
    a,b = list(map(int,input().split()))
    R.append((a,b))
B = []
for i in range(n):
    c,d = list(map(int,input().split()))
    B.append((c,d))

R.sort(reverse=True)#aをx座標でソート
B.sort(key = lambda x:x[1])#bをｙ座標でソート
ans = 0
for i in R:
    for j in range(len(B)):
        if i[0] < B[j][0] and i[1] < B[j][1]:
            ans += 1
            B.pop(j)
            break

print(ans)


from operator import itemgetter
n, *ABCD = map(int, open(0).read().split())
AB = sorted([(a, b) for a, b in zip(ABCD[:2*n:2], ABCD[1:2*n:2])])
CD = sorted([(c, d) for c, d in zip(ABCD[2*n::2], ABCD[2*n+1::2])])

for c, d in CD:
    t_AB = [(a, b) for a, b in AB if a < c and b < d]
    if t_AB:
        t_AB.sort(key=itemgetter(1))
        AB.remove(t_AB[-1])
print(n-len(AB))

import networkx as nx

N=int(input())
ab=[list(map(int,input().split())) for _ in range(N)]
ab=sorted(ab)
cd=[list(map(int,input().split())) for _ in range(N)]
cd=sorted(cd,reverse=True)

G = nx.DiGraph()
for i in range(N):
  G.add_edge('x',i, capacity=1)
  for j in range(N):
    if i == 0:
      G.add_edge(N+j,'y', capacity=1)
    a,b=ab[i]
    c,d=cd[j]
    if a<c and b<d:
      G.add_edge(i,N+j, capacity=1)
    elif a>=c:break

flow_value, flow_dict = nx.maximum_flow(G, 'x', 'y')
print(flow_value)

import sys

read = sys.stdin.read
readline = sys.stdin.readline
readlines = sys.stdin.readlines
sys.setrecursionlimit(10 ** 9)
INF = 1 << 60
MOD = 1000000007


def main():
    N = int(readline())
    P = [0] * (2 * N)
    for i in range(N):
        a, b = list(map(int, readline().split()))
        P[i] = (a, b, 0)
    for i in range(N, 2 * N):
        c, d = list(map(int, readline().split()))
        P[i] = (c, d, 1)

    P.sort(reverse=True)

    vec = [0] * (2 * N + 1)
    ans = 0

    for x, y, p in P:
        if p == 0:
            for i in range(y + 1, 2 * N + 1):
                if vec[i] > 0:
                    vec[i] -= 1
                    ans += 1
                    break
        else:
            vec[y] += 1

    print(ans)
    return


def __starting_point():
    main()

__starting_point()

n = int(input())
aka = [[0 for i in range(2*n)] for j in range(2*n)]
for i in range(n):
    a, b = list(map(int,input().split()))
    aka[a][b] = 1
ao = [tuple(map(int,input().split())) for i in range(n)]
ao.sort()
ans = 0
for x , y in ao:
    flag = False
    for j in reversed(list(range(y))):
        if flag:
            break
        for i in reversed(list(range(x))):
            if aka[i][j] == 1:
                ans += 1
                aka[i][j] = 0
                flag = True
                break
print(ans)


import collections, itertools, copy


class MaximumFlow:
    def __init__(self, G):
        self.G = G

    def ford_fulkerson(self, s, t):
        G = self.G
        G_residue = copy.deepcopy(G)

        def dfs(start, used):
            if start == t:
                return [start]
            for end, cap in list(G_residue[start].items()):
                if cap > 0 and end not in used:
                    used.add(end)
                    ret = dfs(end, used)
                    if ret:
                        return ret + [start]
            return []

        flow_value = 0
        while True:
            root = dfs(s, set([s]))
            if root:
                root = root[::-1]
                residue = min(
                    [G_residue[a][b] for a, b in zip(root, root[1:])])
                flow_value += residue
                for a, b in zip(root, root[1:]):
                    G_residue[a][b] -= residue
                    G_residue[b][a] += residue
            else:
                flow_dict = collections.defaultdict(
                    lambda: collections.defaultdict(int))
                for a in G:
                    for b in G[a]:
                        if G_residue[b][a] > 0:
                            flow_dict[a][b] = G_residue[b][a]
                return (flow_value, flow_dict)


N = int(input())
AB = [[int(_) for _ in input().split()] for _ in range(N)]
CD = [[int(_) for _ in input().split()] for _ in range(N)]
G = collections.defaultdict(lambda: collections.defaultdict(int))
for a, b in AB:
    G[-1][1000 * a + b] = 1
for c, d in CD:
    G[1000 * c + d][-2] = 1
for ab, cd in itertools.product(AB, CD):
    a, b = ab
    c, d = cd
    if a < c and b < d:
        G[1000 * a + b][1000 * c + d] = 1
flow_value, G_residue = MaximumFlow(G).ford_fulkerson(-1, -2)
print(flow_value)


N = int(input())
R = []
B = []
for i in range(2 * N):
    a, b = list(map(int, input().split()))
    if i < N:
        R.append((a, b))
    else:
        B.append((a, b))
B = sorted(B)

ans = 0
checked = set()
p = []
for b in B:
    x1, y1 = b
    tR = [(x2, y2) for x2, y2 in R if x2 < x1]
    tR = sorted(tR, key=lambda p: p[1], reverse=True)
    for x2, y2 in tR:
        if (x2, y2) in checked:
            continue
        if x1 > x2 and y1 > y2:
            ans += 1
            checked.add((x2, y2))
            p.append((b, (x2, y2)))
            break
print(ans)


n = int(input())
reds = sorted([list(map(int,input().split())) for i in range(n)],key=lambda reds: -reds[1])
blues = sorted([list(map(int,input().split())) for i in range(n)])

res = 0

for c,d in blues:
  for a,b in reds:
    if a<c and b<d:
      reds.remove([a,b])
      res+=1
      break
      
print(res)


import sys
INF = 1 << 60
MOD = 10**9 + 7 # 998244353
sys.setrecursionlimit(2147483647)
input = lambda:sys.stdin.readline().rstrip()
from scipy.sparse import coo_matrix
from scipy.sparse.csgraph import maximum_bipartite_matching
def resolve():
    n = int(input())
    A = [tuple(map(int, input().split())) for _ in range(n)]
    B = [tuple(map(int, input().split())) for _ in range(n)]

    weights = []
    rows = []
    columns = []
    for i in range(n):
        ax, ay = A[i]
        for j in range(n):
            bx, by = B[j]
            if ax < bx and ay < by:
                weights.append(1)
                rows.append(i)
                columns.append(j)

    graph = coo_matrix((weights, (rows, columns)), shape = (n, n))
    ans = sum(maximum_bipartite_matching(graph) >= 0)
    print(ans)
resolve()

from sys import stdin
input = stdin.readline


def main():
  N = int(input())
  R = [tuple(map(int, input().split())) for _ in range(N)]
  B = [tuple(map(int, input().split())) for _ in range(N)]

  num_friends = 0
  B.sort(key=lambda x: x[0])

  for ib, b in enumerate(B):
    bx, by = b[0], b[1]

    tmp_r = (-1, -1)

    for ir, r in enumerate(R):
      rx, ry = r[0], r[1]

      if rx < bx and \
         ry < by and \
         tmp_r[1] < ry:
         # b[0] - r[0] < tmp_b[0] - r[0] and \
         # b[1] - r[1] < tmp_b[1] - r[1]:
        tmp_r = r

    if tmp_r == (-1, -1):
      continue
    num_friends += 1
    R.remove(tmp_r)

  print(num_friends)


if(__name__ == '__main__'):
  main()

N = int(input())
ab = [[int(i) for i in input().split()] for _ in range(N)]
cd = [[int(i) for i in input().split()] for _ in range(N)]
 
ab.sort(key = lambda x: x[1], reverse=True)
cd.sort()
 
x = 0
for c, d in cd:
    for a, b in ab:
        if a < c and b < d:
            x += 1
            ab.remove([a, b])
            break
 
print(x)

n = int(input())
ab = [list(map(int,input().split())) for i in range(n)]
cd = [list(map(int,input().split())) for i in range(n)]

ab = sorted(ab, key=lambda x:(x[1], x[0]), reverse=True)
cd = sorted(cd, key=lambda x:(x[0], x[1]))

cnt = 0
i = j = 0
free_ab = [True] * n
while j < n:
    a, b = ab[i][0], ab[i][1]
    c, d = cd[j][0], cd[j][1]
    if a < c and b < d and free_ab[i]:
        cnt += 1
        free_ab[i] = False
        i = 0 
        j += 1
        continue
    elif j <= n-1 and i < n-1:
        i += 1
    elif j < n-1 and i == n-1:
        i = 0
        j += 1
    else:
        break
print(cnt)

n = int(input())
AB = list(list(map(int,input().split())) for _ in range(n))
CD = list(list(map(int,input().split())) for _ in range(n))

CD.sort() # sort x in ascending order
AB.sort(key=lambda z: z[1], reverse=True) # sort x in descending order

vis_r = [False]*(n)
for b in range(n): # ascending order of x
    for r in range(n): # descending order of y
        if not vis_r[r] and AB[r][0] < CD[b][0] and AB[r][1] < CD[b][1]:
            vis_r[r] = True; break

print((sum(vis_r)))


import sys
sys.setrecursionlimit(10**8)
def ii(): return int(sys.stdin.readline())
def mi(): return map(int, sys.stdin.readline().split())
def li(): return list(map(int, sys.stdin.readline().split()))
def li2(N): return [list(map(int, sys.stdin.readline().split())) for _ in range(N)]
def dp2(ini, i, j): return [[ini]*i for _ in range(j)]
#import bisect #bisect.bisect_left(B, a)
#from collections import defaultdict #d = defaultdict(int) d[key] += value
#from collections import Counter # a = Counter(A).most_common()
#from itertools import accumulate #list(accumulate(A))
'''
N = ii()
A = li2(N)
B = li2(N)

A = sorted(A, key=lambda x:x[0])
B = sorted(B, key=lambda x:x[0])

a_ind = 0
b_ind = 0
cnt = 0

while b_ind < N:
    if A[a_ind][0] < B[b_ind][0] and  A[a_ind][1] < B[b_ind][1]:
        cnt += 1
        a_ind += 1
        b_ind += 1
    else:
        b_ind += 1

print(cnt)
'''
'''
#nonlocal ans
ans = 0

def dfs(a_ind, b_ind, cnt):
    if a_ind >= N or b_ind >= N:
        nonlocal ans
        ans = max(ans, cnt)
        return
    if A[a_ind][0] < B[b_ind][0] and  A[a_ind][1] < B[b_ind][1]:
        dfs(a_ind+1, b_ind+1, cnt+1)
    else:
        dfs(a_ind+1, b_ind, cnt)
        dfs(a_ind, b_ind+1, cnt)
        dfs(a_ind+1, b_ind+1, cnt)

dfs(0, 0, 0)

print(ans)
'''

# XとYの二部グラフの最大マッチング X={0,1,2,...|X|-1} Y={0,1,2,...,|Y|-1}
#   edges[x]: xとつながるYの頂点のset
#   matched[y]: yとマッチングされたXの頂点(暫定)

def dfs(v, visited):
    """
    :param v: X側の未マッチングの頂点の1つ
    :param visited: 空のsetを渡す（外部からの呼び出し時）
    :return: 増大路が見つかればTrue
    """
    for u in edges[v]:
        if u in visited:
            continue
        visited.add(u)
        if matched[u] == -1 or dfs(matched[u], visited):
            matched[u] = v
            return True
    return False
 
 
# 標準入力からのグラフ読み取り
#xn, yn, e = map(int, input().split())
N = ii()
xn = N
yn = N
edges = [set() for _ in range(xn)]
matched = [-1] * yn
 
#for _ in range(e):
    #x, y = map(int, input().split())
    #edges[x].add(y)

A = li2(N)
B = li2(N)

for i in range(N):
    for j in range(N):
        if A[i][0] < B[j][0] and  A[i][1] < B[j][1]:
            edges[i].add(j)
 
# 増大路発見に成功したらTrue(=1)。合計することでマッチング数となる
print(sum(dfs(s, set()) for s in range(xn)))

import sys
INF = 1 << 60
MOD = 10**9 + 7 # 998244353
sys.setrecursionlimit(2147483647)
input = lambda:sys.stdin.readline().rstrip()
import networkx as nx
def resolve():
    n = int(input())
    A = [tuple(map(int, input().split())) for _ in range(n)]
    B = [tuple(map(int, input().split())) for _ in range(n)]
    G = nx.Graph()
    G.add_nodes_from(range(n))
    G.add_nodes_from(range(n, 2 * n))
    for i in range(n):
        ax, ay = A[i]
        for j in range(n):
            bx, by = B[j]
            if ax < bx and ay < by:
                G.add_edge(i, n + j)

    A = nx.algorithms.bipartite.maximum_matching(G, top_nodes = range(n))
    print(len(A) // 2)
resolve()

n = int(input())
red, blue = [], []
for _ in range(n):
    a, b = list(map(int, input().split()))
    red.append([a, b, min(a, b)])
for _ in range(n):
    a, b = list(map(int, input().split()))
    blue.append([a, b, min(a, b)])
    
red.sort(key=lambda x: x[1])
blue.sort(key=lambda x: x[0])
status = [False for _ in range(n)]
ans = 0
for i in range(n):
    for j in range(n-1, -1, -1):
        if not status[j]:
            if red[j][0] < blue[i][0] and red[j][1] < blue[i][1]:
                ans += 1
                status[j] = True
                break
print(ans)


N = int(input())
r = []
for i in range(N):
    r.append(list(map(int, input().split())))
b = []
for i in range(N):
    b.append(list(map(int, input().split())))
r = sorted(r, key=lambda x: x[0])
b = sorted(b, key=lambda x: x[0])
r_selected = [False] * N
ans = 0
for i in range(N):
    y_max = -1
    j_selected = -1
    for j in range(N):
        if r_selected[j]:
            continue
        if b[i][0] > r[j][0] and b[i][1] > r[j][1]:
            if y_max < r[j][1]:
                y_max = r[j][1]
                j_selected = j
    if y_max == -1:
        continue
    else:
        r_selected[j_selected] = True
print(r_selected.count(True))

N = int(input())
ab = [list(map(int, input().split())) for _ in range(N)]
cd = [list(map(int, input().split())) for _ in range(N)]
ab.sort(reverse=True)
cd.sort()
p = 0
for c in cd:
    ac = [-1, -1]
    for a in ab:
        if c[0] > a[0] and c[1] > a[1] and ac[1] < a[1]:
            ac = a
    if ac != [-1, -1]:
        p += 1
        ab.remove(ac)

print(p)

N = int(input())
reds = [tuple(map(int, input().split())) for _ in range(N)]
blues = [tuple(map(int, input().split())) for _ in range(N)]

reds.sort(key=lambda x: -x[1])
blues.sort(key=lambda x: x[0])

ans = 0
usedreds = [False]*N
usedblues = [False]*N
for i in range(N):
    if usedreds[i]:
        continue
    a, b = reds[i]
    for j in range(N):
        if usedblues[j]:
            continue
        c, d = blues[j]
        if not (a < c and b < d):
            continue
        ans += 1
        usedreds[i] = True
        usedblues[j] = True
        break

print(ans)

from operator import itemgetter
n, *ABCD = map(int, open(0).read().split())
AB = sorted([(a, b) for a, b in zip(ABCD[:2*n:2], ABCD[1:2*n:2])], key=itemgetter(1))
CD = sorted([(c, d) for c, d in zip(ABCD[2*n::2], ABCD[2*n+1::2])])

for c, d in CD:
    t_AB = [(a, b) for a, b in AB if a < c and b < d]
    if t_AB:
        AB.remove(t_AB[-1])
print(n-len(AB))

n = int(input())
red, blue = [], []
ans = 0
for _ in range(n):
    a, b = list(map(int, input().split()))
    red.append((max(a, b), a, b))
for _ in range(n):
    c, d = list(map(int, input().split()))
    blue.append((min(c, d), c, d))
red.sort(key=lambda x: x[0], reverse=True)
blue.sort(key=lambda x: x[0])
for i in range(n):
    _, xb, yb = blue[i]
    for j in range(n):
        if red[j]:
            _, xr, yr = red[j]
            if xb > xr and yb > yr:
                red[j] = False
                ans += 1
                break
print(ans)


import sys


def resolve():
    readline = sys.stdin.readline    # 1行だけ文字列にする

    N = int(readline())
    NN = 2 * N + 1

    # 青色はx座標をlistのindex,y座標をlistのvalueとして入力，赤は逆
    red = [[] for _ in [0] * NN]
    blue = [[] for _ in [0] * NN]
    for _ in [0] * N:
        a, b = list(map(int, readline().split()))
        red[b].append(a)
    for _ in [0] * N:
        c, d = list(map(int, readline().split()))
        blue[c].append(d)

    # 青色でvalueのy座標について降順(大きい順)でソート
    # 赤色ではvalueのx座標について降順でソート
    # これで青色はx座標は昇順(index)，y座標は降順(value)にソートされる
    # 赤色はy座標が昇順(index)，x座標が降順(value)
    for i in range(NN):
        r = red[i]
        b = blue[i]
        r.sort(reverse=True)
        b.sort(reverse=True)
        r[0:0] = [i]
        b[0:0] = [i]

    # 青点はx座標の昇順で，赤点はy座標の降順
    # 最小のxの青点で最大のyを持つ赤点を選択
    ans = 0
    flag = False
    while blue:
        cd_blue = blue.pop(0)
        c = cd_blue.pop(0)
        if cd_blue:
            for d in cd_blue:
                for ba_red in red[::-1]:
                    b = ba_red[0]
                    if ba_red[1:]:
                        for i in range(1, len(ba_red)):
                            a = ba_red[i]
                            if a <= c and b <= d:
                                ans += 1
                                del red[b][i]
                                flag = True
                                break
                        if flag:
                            break
                if flag:
                    flag = False
                    break
    print(ans)


resolve()


"""
青はxの昇順、赤はyの降順に並び替え、xの小さい青からペアを探していく。x座標の検証において、小さい青の候補に入る赤は今後の青の候補にも
なるため、y座標ができるだけ大きい赤とペアを作るようにする。

"""
n = int(input())
red = [[0] * 2 for _ in range(n)]
blue = [[0] * 2 for _ in range(n)]
for i in range(n):
    red[i][1], red[i][0] = list(map(int, input().split()))
for i in range(n):
    blue[i][0], blue[i][1] = list(map(int, input().split()))

red.sort(reverse=True)
blue.sort()
ans = 0
usedred = [False] * n
for i in range(n):
    for j in range(n):
        if blue[i][0] > red[j][1] and blue[i][1] > red[j][0] and usedred[j] != True:
            ans += 1
            usedred[j] = True
            break

print(ans)


from heapq import heappop, heappush

N = int(input())
R = []
B = []
YFlag = [True]*(2*N)

for _ in range(N):
  a, b = map(int, input().split())
  R.append((a, b))

for _ in range(N):
  c, d = map(int, input().split())
  B.append((c, d))

B.sort()

ans = 0
for c, d in B:
  cand = []
  for a, b in R:
    if a < c and b < d and YFlag[b]:
      cand.append(b)
  if cand:
    ans += 1
    YFlag[max(cand)] = False

print(ans)


n = int(input().strip())
red = [list(map(int, input().split())) for i in range(n)]
blue = [list(map(int, input().split())) for j in range(n)]

for i in range(n):
    '''
    kagi_r = [min(red[i][0], red[i][1]), max(red[i][0], red[i][1])]
    kagi_b = [min(blue[i][0], blue[i][1]), max(blue[i][0], blue[i][1])]
    red[i] = red[i] + kagi_r
    blue[i] = blue[i] + kagi_b
    '''
red.sort(key=lambda x: (x[0], x[1]), reverse=True)
blue.sort(key=lambda x: x[1])
flg_r = [0]*n
cnt = 0

for i in range(n):
    for j in range(n):
        if flg_r[j]:
            continue
        if red[j][0] < blue[i][0] and red[j][1] < blue[i][1]:
            flg_r[j] = 1
            cnt += 1
            break

print(cnt)



N = int(input())
red = [list(map(int, input().split())) for _ in range(N)]
blue = [list(map(int, input().split())) for _ in range(N)]
blue = sorted(blue, key=lambda x: x[0])

used = []
for i in range(N):
    c, d = blue[i]
    m, tmp = -1, -1
    for j in range(N):
        if j in used:
            continue
        a, b = red[j]
        if a < c and b < d:
            if b > m:
                m = b
                tmp = j
    if tmp != -1:
        used.append(tmp)
print(len(used))

import networkx as nx

N = int(input())
ABs = [tuple(map(int, input().split())) for _ in range(N)]
CDs = [tuple(map(int, input().split())) for _ in range(N)]

# 0 <= i <   N  -> i: ABs[i]
# N <= i < 2*N  -> i: CDs[i-N]
# i == 2*N+1    -> start
# i == 2*N+2    -> goal

DG = nx.DiGraph()
DG.add_nodes_from(list(range(2 * N + 3)))
for i in range(N):
    for j in range(N):
        if ABs[i][0] < CDs[j][0] and ABs[i][1] < CDs[j][1]:
            DG.add_edge(i, j + N, capacity = 1)

DG.add_edges_from([(2 * N + 1, i, {"capacity":1}) for i in range(N)])
DG.add_edges_from([(i, 2 * N + 2, {"capacity":1}) for i in range(N, 2*N)])

print((nx.maximum_flow_value(DG, 2 * N + 1, 2 * N + 2)))


def main():
    n = int(input())
    B = []
    g = [[0]*(2*n) for _ in range(2*n)]
    for _ in range(n):
        a,b  = map(int,input().split())
        g[b][a] = 1
    for _ in range(n):
        c,d = map(int,input().split())
        B.append((c,d))
    B.sort()
    ans = 0
    for i,j in B:
        f = 0
        for y in range(j,-1,-1):
            for x in range(i,-1,-1):
                if g[y][x]:
                    ans += 1
                    f = 1
                    g[y][x] = 0
                    break
            if f:
                break
    print(ans)

main()

import sys
input=sys.stdin.readline

from collections import deque
class HopcroftKarp:
    def __init__(self, N0, N1):
        self.N0 = N0
        self.N1 = N1
        self.N = N = 2+N0+N1
        self.G = [[] for i in range(N)]
        for i in range(N0):
            forward = [2+i, 1, None]
            forward[2] = backward = [0, 0, forward]
            self.G[0].append(forward)
            self.G[2+i].append(backward)
        self.backwards = bs = []
        for i in range(N1):
            forward = [1, 1, None]
            forward[2] = backward = [2+N0+i, 0, forward]
            bs.append(backward)
            self.G[2+N0+i].append(forward)
            self.G[1].append(backward)

    def add_edge(self, fr, to):
        #assert 0 <= fr < self.N0
        #assert 0 <= to < self.N1
        v0 = 2 + fr
        v1 = 2 + self.N0 + to
        forward = [v1, 1, None]
        forward[2] = backward = [v0, 0, forward]
        self.G[v0].append(forward)
        self.G[v1].append(backward)

    def bfs(self):
        G = self.G
        level = [None]*self.N
        deq = deque([0])
        level[0] = 0
        while deq:
            v = deq.popleft()
            lv = level[v] + 1
            for w, cap, _ in G[v]:
                if cap and level[w] is None:
                    level[w] = lv
                    deq.append(w)
        self.level = level
        return level[1] is not None

    def dfs(self, v, t):
        if v == t:
            return 1
        level = self.level
        for e in self.it[v]:
            w, cap, rev = e
            if cap and level[v] < level[w] and self.dfs(w, t):
                e[1] = 0
                rev[1] = 1
                return 1
        return 0

    def flow(self):
        flow = 0
        G = self.G
        bfs = self.bfs; dfs = self.dfs
        while bfs():
            *self.it, = map(iter, G)
            while dfs(0, 1):
                flow += 1
        return flow

    def matching(self):
        return [cap for _, cap, _ in self.backwards]

n=int(input())

solve=HopcroftKarp(n,n)

red,blue=[],[]

for i in range(n):
    a,b=map(int,input().split())
    red.append([a,b])

for i in range(n):
    c,d=map(int,input().split())
    blue.append([c,d])


for i in range(n):
    for j in range(n):
        if red[i][0]<blue[j][0] and red[i][1]<blue[j][1]:
            solve.add_edge(i,j)


print(solve.flow())