Arkady has got an infinite plane painted in color 0. Then he draws n rectangles filled with paint with sides parallel to the Cartesian coordinate axes, one after another. The color of the i-th rectangle is i (rectangles are enumerated from 1 to n in the order he draws them). It is possible that new rectangles cover some of the previous ones completely or partially.

Count the number of different colors on the plane after Arkady draws all the rectangles.

Input

The first line contains a single integer n (1 ≤ n ≤ 100 000) — the number of rectangles.

The i-th of the next n lines contains 4 integers x_1, y_1, x_2 and y_2 (-10^9 ≤ x_1 < x_2 ≤ 10^9, -10^9 ≤ y_1 < y_2 ≤ 10^9) — the coordinates of corners of the i-th rectangle.

Output

In the single line print the number of different colors in the plane, including color 0.

Examples

Input

5
-1 -1 1 1
-4 0 0 4
0 0 4 4
-4 -4 0 0
0 -4 4 0


Output

5

Input

4
0 0 4 4
-4 -4 0 0
0 -4 4 0
-2 -4 2 4


Output

5

Note

<image> That's how the plane looks in the first sample

<image> That's how the plane looks in the second sample

0 = white, 1 = cyan, 2 = blue, 3 = purple, 4 = yellow, 5 = red. 
#include <bits/stdc++.h>
using namespace std;
inline int readint() {
  int a = 0;
  char c = getchar(), f = 1;
  for (; c < '0' || c > '9'; c = getchar())
    if (c == '-') f = -f;
  for (; '0' <= c && c <= '9'; c = getchar())
    a = (a << 3) + (a << 1) + (c ^ 48);
  return a * f;
}
const int infty = (1 << 30) - 1;
struct BestHeap {
  priority_queue<int> pq, bad;
  void push(int x) { pq.push(x); }
  void erase(int x) { bad.push(x); }
  void pop() { pq.pop(); }
  void clear() {
    while (!pq.empty()) pq.pop();
    while (!bad.empty()) bad.pop();
  }
  bool empty() {
    while (!pq.empty() && !bad.empty())
      if (pq.top() == bad.top())
        pq.pop(), bad.pop();
      else if (bad.top() > pq.top())
        bad.pop();
      else
        break;
    return pq.empty();
  }
  int top() {
    if (!empty()) return pq.top();
    return -infty;
  }
};
const int MaxN = 400005;
int n, m;
bool good[MaxN];
namespace SgTree {
const int MaxM = MaxN << 2;
BestHeap all[MaxM], s[MaxM];
int lazy[MaxM], mn[MaxM];
void pushUp(int o, int l, int r) {
  if (l != r)
    mn[o] = min(mn[o << 1], mn[o << 1 | 1]);
  else
    mn[o] = 0;
  mn[o] = max(mn[o], all[o].top());
}
void pushDown(int o, int l, int r) {
  if (lazy[o] > n) return;
  int t = max(lazy[o], mn[o]);
  for (; s[o].top() >= t; s[o].pop()) good[s[o].top()] = true;
  if (l != r) {
    t = max(lazy[o], all[o].top());
    lazy[o << 1] = min(lazy[o << 1], t);
    lazy[o << 1 | 1] = min(lazy[o << 1 | 1], t);
  }
  lazy[o] = infty;
}
void add(int ql, int qr, int qv, int pre = 0, int o = 1, int l = 1, int r = m) {
  pushDown(o, l, r);
  if (ql <= l && r <= qr) {
    if (max(pre, mn[o]) <= qv)
      good[qv] = true;
    else
      s[o].push(qv);
    all[o].push(qv);
    return pushUp(o, l, r);
  }
  int mid = (l + r) >> 1;
  pre = max(pre, all[o].top());
  if (ql <= mid) add(ql, qr, qv, pre, o << 1, l, mid);
  if (mid < qr) add(ql, qr, qv, pre, o << 1 | 1, mid + 1, r);
  return pushUp(o, l, r);
}
void del(int ql, int qr, int qv, int pre = 0, int o = 1, int l = 1, int r = m) {
  pushDown(o, l, r);
  if (ql <= l && r <= qr) {
    s[o].erase(qv), all[o].erase(qv);
    lazy[o] = pre;
    return pushUp(o, l, r);
  }
  int mid = (l + r) >> 1, t = max(pre, all[o].top());
  if (ql <= mid) del(ql, qr, qv, t, o << 1, l, mid);
  if (mid < qr) del(ql, qr, qv, t, o << 1 | 1, mid + 1, r);
  pushUp(o, l, r);
  t = max(pre, mn[o]);
  for (; s[o].top() >= t; s[o].pop()) good[s[o].top()] = true;
}
void clear(int o = 1, int l = 1, int r = m) {
  lazy[o] = infty, mn[o] = 0;
  all[o].clear(), s[o].clear();
  if (l == r) return;
  clear(o << 1, l, (l + r) >> 1);
  clear(o << 1 | 1, (l + r) / 2 + 1, r);
}
void debug(int qid, int o = 1, int l = 1, int r = m) {
  if (lazy[o] != infty) printf("[%d,%d]: %d\n", l, r, lazy[o]);
  if (l == r) return;
  if (qid <= ((l + r) >> 1))
    debug(qid, o << 1, l, (l + r) >> 1);
  else
    debug(qid, o << 1 | 1, (l + r) / 2 + 1, r);
}
}  // namespace SgTree
struct Command {
  int opt, ly, ry, id, x;
  bool operator<(const Command& t) const {
    if (x != t.x) return x < t.x;
    if (opt != t.opt) return opt > t.opt;
    return opt * id > opt * t.id;
  }
};
Command q[MaxN];
int item[MaxN];
int LiSan(int* l, int* r) {
  memcpy(item, l, (r - l) << 2);
  sort(item, item + (r - l));
  int* q = unique(item, item + (r - l));
  for (int* i = l; i != r; ++i) *i = lower_bound(item, q, *i) - item + 1;
  return q - item;
}
int tmpy[MaxN];
int main() {
  n = readint();
  for (int i = 0; i < n; ++i) {
    q[i << 1].x = readint();
    tmpy[i << 1] = readint();
    q[i << 1 | 1].x = readint();
    tmpy[i << 1 | 1] = readint() - 1;
    tmpy[(n << 1) + i] = tmpy[i << 1 | 1] + 1;
  }
  m = LiSan(tmpy, tmpy + n * 3);
  for (int i = 0; i < n; ++i) {
    q[i << 1].opt = 1, q[i << 1 | 1].opt = -1;
    q[i << 1].ly = q[i << 1 | 1].ly = tmpy[i << 1];
    q[i << 1].ry = q[i << 1 | 1].ry = tmpy[i << 1 | 1];
    q[i << 1].id = q[i << 1 | 1].id = i + 1;
  }
  sort(q, q + (n << 1));
  SgTree::clear();
  for (int i = 0; i < (n << 1); ++i) {
    if (q[i].opt == 1)
      SgTree::add(q[i].ly, q[i].ry, q[i].id);
    else
      SgTree::del(q[i].ly, q[i].ry, q[i].id);
  }
  int ans = 1;
  for (int i = 1; i <= n; ++i) ans += good[i];
  printf("%d\n", ans);
  return 0;
}
