Problem: This problem differs from the previous problem only in constraints.

Petya decided to visit Byteland during the summer holidays. It turned out that the history of this country is quite unusual.

Initially, there were n different countries on the land that is now Berland. Each country had its own territory that was represented as a rectangle on the map. The sides of the rectangle were parallel to the axes, and the corners were located at points with integer coordinates. Territories of no two countries intersected, but it was possible that some territories touched each other. As time passed, sometimes two countries merged into one. It only happened if the union of their territories was also a rectangle. In the end only one country remained — Byteland.

Initially, each country had a rectangular castle inside its territory. Its sides were parallel to the axes and its corners had integer coordinates. Some castles might touch the border of the corresponding country and sides or other castles. Miraculously, after all the unions the castles are still intact. Unfortunately, their locations are the only information we have to restore the initial territories of the countries.

<image> The possible formation of Byteland. The castles are shown in blue. 

Petya wonders why no information about the initial countries remained. He suspected that the whole story is a fake. You were recommended to him as a smart person. Please check whether or not there exists a possible set of initial territories that could make the story true.

Input

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

Each of the next n lines contains four integers a_i, b_i, c_i, d_i (0 ≤ a_i < c_i ≤ 10^9, 0 ≤ b_i < d_i ≤ 10^9) — the coordinates of the i-th castle, where (a_i, b_i) are the coordinates of the lower left corner and (c_i, d_i) are the coordinates of the upper right corner.

It is guaranteed that no two castles intersect, however, they may touch.

Output

If there exists a possible set of territories that satisfies the story, print "YES", otherwise print "NO".

You can print each letter in any case (upper or lower).

Examples

Input


4
0 0 1 2
0 2 1 3
1 0 2 1
1 1 2 3


Output


YES


Input


4
0 0 2 1
1 2 3 3
2 0 3 2
0 1 1 3


Output


NO

Note

The castles in the first and second examples are shown on the pictures below. 

<image> <image>

Solution (in CPP):

Solution:
#include <bits/stdc++.h>
using namespace std;
const int N = 1100009, smN = 400009;
int a, b, c, d, e, i, j, ii, jj, zx, xc, za, l, r, z;
pair<pair<int, int>, pair<int, int> > p[100009];
int segx[N], segx2[N], segX[N];
int segy[N], segy2[N], segY[N];
set<int> setX[smN], setY[smN];
void pushdownx(int q, int w, int rr) {
  if (q != w) {
    segx2[rr * 2] += segx2[rr];
    segx2[rr * 2 + 1] += segx2[rr];
  }
  segx[rr] += segx2[rr];
  segx2[rr] = 0;
}
void updx(int q, int w, int rr) {
  pushdownx(q, w, rr);
  if (w < l || q > r) return;
  if (q >= l && w <= r) {
    segx2[rr] = z;
    pushdownx(q, w, rr);
    return;
  }
  updx(q, (q + w) / 2, rr * 2);
  updx((q + w) / 2 + 1, w, rr * 2 + 1);
  segx[rr] = min(segx[rr * 2], segx[rr * 2 + 1]);
}
void readx0(int q, int w, int rr) {
  pushdownx(q, w, rr);
  if (q > r || w < l) return;
  if (segx[rr] != 0) return;
  if (q == w) {
    if (segx[rr] == 0) {
      z = q;
    }
    return;
  }
  if (q >= l && w <= r) {
    pushdownx(q, (q + w) / 2, rr * 2);
    pushdownx((q + w) / 2 + 1, w, rr * 2 + 1);
    if (segx[rr * 2] == 0) {
      readx0(q, (q + w) / 2, rr * 2);
    } else {
      readx0((q + w) / 2 + 1, w, rr * 2 + 1);
    }
    return;
  }
  readx0(q, (q + w) / 2, rr * 2);
  if (z != 0) return;
  readx0((q + w) / 2 + 1, w, rr * 2 + 1);
}
void pushdowny(int q, int w, int rr) {
  if (q != w) {
    segy2[rr * 2] += segy2[rr];
    segy2[rr * 2 + 1] += segy2[rr];
  }
  segy[rr] += segy2[rr];
  segy2[rr] = 0;
}
void updy(int q, int w, int rr) {
  pushdowny(q, w, rr);
  if (w < l || q > r) return;
  if (q >= l && w <= r) {
    segy2[rr] = z;
    pushdowny(q, w, rr);
    return;
  }
  updy(q, (q + w) / 2, rr * 2);
  updy((q + w) / 2 + 1, w, rr * 2 + 1);
  segy[rr] = min(segy[rr * 2], segy[rr * 2 + 1]);
}
void ready0(int q, int w, int rr) {
  pushdowny(q, w, rr);
  if (q > r || w < l) return;
  if (segy[rr] != 0) return;
  if (q == w) {
    if (segy[rr] == 0) {
      z = q;
    }
    return;
  }
  if (q >= l && w <= r) {
    pushdowny(q, (q + w) / 2, rr * 2);
    pushdowny((q + w) / 2 + 1, w, rr * 2 + 1);
    if (segy[rr * 2] == 0) {
      ready0(q, (q + w) / 2, rr * 2);
    } else {
      ready0((q + w) / 2 + 1, w, rr * 2 + 1);
    }
    return;
  }
  ready0(q, (q + w) / 2, rr * 2);
  if (z != 0) return;
  ready0((q + w) / 2 + 1, w, rr * 2 + 1);
}
void updX(int q, int w) {
  if (q == 0) return;
  segX[q] += w;
  updX(q / 2, w);
}
void readX(int q, int w, int rr) {
  if (q > r || w < l) return;
  if (q >= l && w <= r) {
    z += segX[rr];
    return;
  }
  readX(q, (q + w) / 2, rr * 2);
  readX((q + w) / 2 + 1, w, rr * 2 + 1);
}
void readX1(int q, int w, int rr) {
  if (q > r || w < l) return;
  if (segX[rr] == 0) return;
  if (q == w) {
    if (segX[rr] != 0) {
      z = q;
    }
    return;
  }
  if (q >= l && w <= r) {
    if (segX[rr * 2] != 0) {
      readX1(q, (q + w) / 2, rr * 2);
    } else {
      readX1((q + w) / 2 + 1, w, rr * 2 + 1);
    }
    return;
  }
  readX1(q, (q + w) / 2, rr * 2);
  if (z != 0) return;
  readX1((q + w) / 2 + 1, w, rr * 2 + 1);
}
void updY(int q, int w) {
  if (q == 0) return;
  segY[q] += w;
  updY(q / 2, w);
}
void readY(int q, int w, int rr) {
  if (q > r || w < l) return;
  if (q >= l && w <= r) {
    z += segY[rr];
    return;
  }
  readY(q, (q + w) / 2, rr * 2);
  readY((q + w) / 2 + 1, w, rr * 2 + 1);
}
void readY1(int q, int w, int rr) {
  if (q > r || w < l) return;
  if (segY[rr] == 0) return;
  if (q == w) {
    if (segY[rr] != 0) {
      z = q;
    }
    return;
  }
  if (q >= l && w <= r) {
    if (segY[rr * 2] != 0) {
      readY1(q, (q + w) / 2, rr * 2);
    } else {
      readY1((q + w) / 2 + 1, w, rr * 2 + 1);
    }
    return;
  }
  readY1(q, (q + w) / 2, rr * 2);
  if (z != 0) return;
  readY1((q + w) / 2 + 1, w, rr * 2 + 1);
}
void updplus(int q) {
  int ll = l, rr = r, zz = z;
  swap(q, i);
  l = p[i].first.first;
  r = p[i].first.second - 1;
  z = 1;
  if (l <= r) updx(1, za, 1);
  l = p[i].second.first;
  r = p[i].second.second - 1;
  z = 1;
  if (l <= r) updy(1, za, 1);
  setX[p[i].first.first].insert(i);
  updX(p[i].first.first + za - 1, 1);
  setY[p[i].second.first].insert(i);
  updY(p[i].second.first + za - 1, 1);
  swap(q, i);
  l = ll;
  r = rr;
  z = zz;
}
void updminus(int q) {
  int ll = l, rr = r, zz = z;
  swap(q, i);
  l = p[i].first.first;
  r = p[i].first.second - 1;
  z = -1;
  if (l <= r) updx(1, za, 1);
  l = p[i].second.first;
  r = p[i].second.second - 1;
  z = -1;
  if (l <= r) updy(1, za, 1);
  setX[p[i].first.first].erase(setX[p[i].first.first].lower_bound(i));
  updX(p[i].first.first + za - 1, -1);
  setY[p[i].second.first].erase(setY[p[i].second.first].lower_bound(i));
  updY(p[i].second.first + za - 1, -1);
  swap(q, i);
  l = ll;
  r = rr;
  z = zz;
}
void rec(int q, int w, int qq, int ww) {
  if (q > w || qq > ww) return;
  l = q;
  r = w;
  z = 0;
  readX(1, za, 1);
  if (z == 0) return;
  if (z == 1) {
    l = q;
    r = w;
    z = 0;
    readX1(1, za, 1);
    z = (*setX[z].begin());
    updminus(z);
    return;
  }
  l = q;
  r = w;
  z = 0;
  readX1(1, za, 1);
  l = z;
  r = w - 1;
  z = 0;
  if (l <= r) readx0(1, za, 1);
  int CO = 0;
  while (CO == 0) {
    CO = 1;
    if (z != 0) {
      int qw = 0, we = 0, Z = z;
      l = q;
      r = Z;
      z = 0;
      if (l <= r) readX(1, za, 1);
      qw = z;
      l = Z + 1;
      r = w;
      z = 0;
      if (l <= r) readX(1, za, 1);
      we = z;
      if (qw == 0 || we == 0) break;
      if (qw <= we) {
        l = q;
        r = Z;
        vector<int> P;
        while (l <= Z) {
          z = 0;
          if (l <= r) readX1(1, za, 1);
          l = z;
          if (l > Z || z == 0) break;
          while (setX[l].size()) {
            P.push_back((*setX[l].begin()));
            updminus((*setX[l].begin()));
          }
          l++;
        }
        rec(Z + 1, w, qq, ww);
        while (P.size()) {
          updplus(P[P.size() - 1]);
          P.pop_back();
        }
        rec(q, Z, qq, ww);
      } else {
        l = Z + 1;
        r = w;
        vector<int> P;
        while (l <= w) {
          z = 0;
          if (l <= r) readX1(1, za, 1);
          l = z;
          if (l > w || z == 0) break;
          while (setX[l].size()) {
            P.push_back((*setX[l].begin()));
            updminus((*setX[l].begin()));
          }
          l++;
        }
        rec(q, Z, qq, ww);
        while (P.size()) {
          updplus(P[P.size() - 1]);
          P.pop_back();
        }
        rec(Z + 1, w, qq, ww);
      }
      return;
    }
  }
  l = qq;
  r = ww;
  z = 0;
  readY1(1, za, 1);
  l = z;
  r = ww - 1;
  z = 0;
  if (l <= r) ready0(1, za, 1);
  CO = 0;
  while (CO == 0) {
    CO = 1;
    if (z != 0) {
      int qw = 0, we = 0, Z = z;
      l = qq;
      r = Z;
      z = 0;
      if (l <= r) readY(1, za, 1);
      qw = z;
      l = Z + 1;
      r = ww;
      z = 0;
      if (l <= r) readY(1, za, 1);
      we = z;
      if (qw == 0 || we == 0) break;
      if (qw <= we) {
        l = qq;
        r = Z;
        vector<int> P;
        while (l <= Z) {
          z = 0;
          if (l <= r) readY1(1, za, 1);
          l = z;
          if (l > Z || z == 0) break;
          while (setY[l].size()) {
            P.push_back((*setY[l].begin()));
            updminus((*setY[l].begin()));
          }
          l++;
        }
        rec(q, w, Z + 1, ww);
        while (P.size()) {
          updplus(P[P.size() - 1]);
          P.pop_back();
        }
        rec(q, w, qq, Z);
      } else {
        l = Z + 1;
        r = ww;
        vector<int> P;
        while (l <= ww) {
          z = 0;
          if (l <= r) readY1(1, za, 1);
          l = z;
          if (l > ww || z == 0) break;
          while (setY[l].size()) {
            P.push_back((*setY[l].begin()));
            updminus((*setY[l].begin()));
          }
          l++;
        }
        rec(q, w, qq, Z);
        while (P.size()) {
          updplus(P[P.size() - 1]);
          P.pop_back();
        }
        rec(q, w, Z + 1, ww);
      }
      return;
    }
  }
  cout << "NO";
  exit(0);
}
int main() {
  ios_base::sync_with_stdio(false), cin.tie(0), cout.tie(0);
  cin >> a;
  map<int, int> mp;
  map<int, int>::iterator it;
  for (i = 1; i <= a; i++) {
    cin >> p[i].first.first >> p[i].second.first >> p[i].first.second >>
        p[i].second.second;
    p[i].first.second--;
    p[i].second.second--;
    mp[p[i].first.first] = 1;
    mp[p[i].first.second] = 1;
    mp[p[i].second.first] = 1;
    mp[p[i].second.second] = 1;
  }
  zx = 2;
  for (it = mp.begin(); it != mp.end(); it++) {
    zx++;
    (*it).second = zx;
  }
  for (i = 1; i <= a; i++) {
    p[i].first.first = mp[p[i].first.first];
    p[i].first.second = mp[p[i].first.second];
    p[i].second.first = mp[p[i].second.first];
    p[i].second.second = mp[p[i].second.second];
  }
  za = 1;
  while (za < 400005) za *= 2;
  for (i = 1; i <= a; i++) {
    updplus(i);
  }
  rec(1, 400007, 1, 400007);
  cout << "YES";
  return 0;
}