#include <bits/stdc++.h>
using namespace std;
const int INF = (1 << 30);
const int MAXN = 100000;
struct node {
  int le, ri;
  set<int> Set;
  int mx, mn;
} tree[24 * MAXN + 5];
bool tag[MAXN + 5];
void pushup(int x) {
  if (tree[x].le == tree[x].ri)
    tree[x].mx = tree[x].mn = *tree[x].Set.rbegin();
  else {
    tree[x].mn =
        max(*tree[x].Set.rbegin(), min(tree[x << 1].mn, tree[x << 1 | 1].mn));
    tree[x].mx =
        max(*tree[x].Set.rbegin(), max(tree[x << 1].mx, tree[x << 1 | 1].mx));
  }
  if (tree[x].mx < tree[x].mn) tree[x].mx = -1;
  if (tree[x].mx != -1 && tag[tree[x].mx]) tree[x].mx = -1;
}
void build(int x, int l, int r) {
  tree[x].le = l, tree[x].ri = r;
  tree[x].mx = tree[x].mn = 0;
  tree[x].Set.clear();
  tree[x].Set.insert(0);
  if (l == r) return;
  int mid = (l + r) >> 1;
  build(x << 1, l, mid);
  build(x << 1 | 1, mid + 1, r);
}
void modify(int x, int l, int r, int k, int type) {
  if (l > tree[x].ri || r < tree[x].le) return;
  if (l <= tree[x].le && tree[x].ri <= r) {
    if (type)
      tree[x].Set.insert(k);
    else
      tree[x].Set.erase(k);
    pushup(x);
    return;
  }
  modify(x << 1, l, r, k, type);
  modify(x << 1 | 1, l, r, k, type);
  pushup(x);
}
void update(int x, int l, int r) {
  if (l > tree[x].ri || r < tree[x].le) return;
  if (l <= tree[x].le && tree[x].ri <= r) {
    pushup(x);
    return;
  }
  update(x << 1, l, r);
  update(x << 1 | 1, l, r);
  pushup(x);
}
int N;
int Xa[MAXN + 5], Xb[MAXN + 5], Ya[MAXN + 5], Yb[MAXN + 5];
int dct[2][6 * MAXN + 5], dcnt[2];
void discrete() {
  for (int i = 0; i < 2; i++) sort(dct[i] + 1, dct[i] + dcnt[i] + 1);
  for (int i = 0; i < 2; i++)
    dcnt[i] = unique(dct[i] + 1, dct[i] + dcnt[i] + 1) - dct[i] - 1;
  for (int i = 1; i <= N; i++) {
    Xa[i] = lower_bound(dct[0] + 1, dct[0] + dcnt[0] + 1, Xa[i]) - dct[0];
    Xb[i] = lower_bound(dct[0] + 1, dct[0] + dcnt[0] + 1, Xb[i]) - dct[0];
    Ya[i] = lower_bound(dct[1] + 1, dct[1] + dcnt[1] + 1, Ya[i]) - dct[1];
    Yb[i] = lower_bound(dct[1] + 1, dct[1] + dcnt[1] + 1, Yb[i]) - dct[1];
  }
}
void insert_dct(int val, int type) { dct[type][++dcnt[type]] = val; }
struct query {
  int le, ri, num;
  bool type;
  query(int _l = 0, int _r = 0, int _n = 0, bool _t = 0)
      : le(_l), ri(_r), num(_n), type(_t) {}
};
vector<query> vec[6 * MAXN + 5];
int main() {
  scanf("%d", &N);
  for (int i = 1; i <= N; i++) {
    scanf("%d%d%d%d", &Xa[i], &Ya[i], &Xb[i], &Yb[i]);
    Xb[i]--, Yb[i]--;
    insert_dct(Xa[i], 0);
    insert_dct(Xa[i] + 1, 0);
    insert_dct(Xa[i] - 1, 0);
    insert_dct(Xb[i], 0);
    insert_dct(Xb[i] + 1, 0);
    insert_dct(Xb[i] - 1, 0);
    insert_dct(Ya[i], 1);
    insert_dct(Ya[i] + 1, 1);
    insert_dct(Ya[i] - 1, 1);
    insert_dct(Yb[i], 1);
    insert_dct(Yb[i] + 1, 1);
    insert_dct(Yb[i] - 1, 1);
  }
  discrete();
  for (int i = 1; i <= N; i++) {
    vec[Xa[i]].push_back(query(Ya[i], Yb[i], i, 1));
    vec[Xb[i] + 1].push_back(query(Ya[i], Yb[i], i, 0));
  }
  build(1, 1, dcnt[1]);
  Ya[0] = 1;
  Yb[0] = dcnt[1];
  for (int i = 1; i <= dcnt[0]; i++) {
    for (int j = 0; j < vec[i].size(); j++)
      modify(1, vec[i][j].le, vec[i][j].ri, vec[i][j].num, vec[i][j].type);
    while (tree[1].mx != -1) {
      tag[tree[1].mx] = true;
      update(1, Ya[tree[1].mx], Yb[tree[1].mx]);
    }
  }
  int ans = 0;
  for (int i = 0; i <= N; i++)
    if (tag[i]) ans++;
  printf("%d\n", ans);
}
