#include <bits/stdc++.h>
using namespace std;
const int MaxN = 1003 * 2;
const int INF = 1000000000;
struct Line {
  int L, R;
  int y;
  int pos;
  Line() {}
  Line(int L, int R, int y, int pos) : L(L), R(R), y(y), pos(pos) {}
};
inline bool cmp1(const Line& a, const Line& b) {
  if (a.L != b.L) return a.L < b.L;
  return a.R < b.R;
}
inline bool cmp2(const Line& a, const Line& b) {
  if (a.R != b.R) return a.R < b.R;
  return a.L < b.L;
}
inline bool cmp3(const Line& a, const Line& b) { return a.y < b.y; }
struct SegTree {
  int BIT[MaxN << 2], COL[MaxN << 2];
  int N = 0;
  void pushUP(int po) { BIT[po] = max(BIT[(po << 1)], BIT[((po << 1) | 1)]); }
  void pushDown(int po) {
    if (COL[po]) {
      BIT[(po << 1)] = max(BIT[(po << 1)], BIT[po]);
      BIT[((po << 1) | 1)] = max(BIT[((po << 1) | 1)], BIT[po]);
      COL[po] = 0;
      COL[(po << 1)] = COL[((po << 1) | 1)] = 1;
    }
  }
  void update(int ul, int ur, int val, int L, int R, int po) {
    if (ul <= L && ur >= R) {
      BIT[po] = max(BIT[po], val);
      COL[po] = 1;
      return;
    }
    pushDown(po);
    int M = (L + R) >> 1;
    if (ul <= M) update(ul, ur, val, L, M, (po << 1));
    if (ur > M) update(ul, ur, val, M + 1, R, ((po << 1) | 1));
    pushUP(po);
  }
  int query(int x, int L, int R, int po) {
    if (L == R) return BIT[po];
    pushDown(po);
    int M = (L + R) >> 1;
    if (x <= M)
      return query(x, L, M, (po << 1));
    else
      return query(x, M + 1, R, ((po << 1) | 1));
  }
  void Init(int len, int val) {
    N = len;
    for (int i = 0; i < (MaxN << 2); ++i) {
      BIT[i] = val;
      COL[i] = 0;
    }
  }
  void Update(int L, int R, int val) {
    if (L > R) return;
    update(L, R, val, 1, N, 1);
  }
  int Query(int x) {
    int rrr = query(x, 1, N, 1);
    return rrr;
  }
};
SegTree tree;
int cou = 0;
Line heng[MaxN];
Line shu[MaxN];
pair<double, double> dian[MaxN];
int LMax[MaxN], RMax[MaxN];
int UMax[MaxN], DMax[MaxN];
int uni_x[MaxN], uni_y[MaxN];
int cou_x, cou_y;
void GetData(Line heng[], Line shu[], int LMax[], int RMax[]) {
  sort(shu + 1, shu + cou + 1, cmp3);
  sort(heng + 1, heng + cou + 1, cmp1);
  tree.Init(cou, 0);
  for (int i = 1, pos = 1; i <= cou; ++i) {
    while (pos <= cou && shu[pos].y <= heng[i].L) {
      tree.Update(shu[pos].L + 1, shu[pos].R - 1, shu[pos].y);
      ++pos;
    }
    LMax[heng[i].pos] = tree.Query(heng[i].y);
  }
  sort(heng + 1, heng + cou + 1, cmp2);
  tree.Init(cou, -INF);
  for (int i = cou, pos = cou; i >= 1; --i) {
    while (pos >= 1 && shu[pos].y >= heng[i].R) {
      tree.Update(shu[pos].L + 1, shu[pos].R - 1, -shu[pos].y);
      --pos;
    }
    RMax[heng[i].pos] = -tree.Query(heng[i].y);
  }
}
inline int Unique(int buf[], int len, int x) {
  return lower_bound(buf + 1, buf + len + 1, x) - buf;
}
struct Node {
  int L, D, R, U;
  Node() {}
  Node(int L, int D, int R, int U) : L(L), D(D), R(R), U(U) {}
};
queue<Node> que;
bool Solve1(int L, int D, int R, int U) {
  int ccc = 0;
  int minnH = INF, maxnH = -INF;
  int minnS = INF, maxnS = -INF;
  double xx, yy;
  for (int i = 1; i <= cou; ++i) {
    xx = dian[heng[i].pos].first;
    yy = dian[heng[i].pos].second;
    if (xx >= L && xx <= R && yy >= D && yy <= U) {
      ++ccc;
      minnH = min(minnH, heng[i].y);
      maxnH = max(maxnH, heng[i].y);
    }
    xx = dian[shu[i].pos].first;
    yy = dian[shu[i].pos].second;
    if (xx >= L && xx <= R && yy >= D && yy <= U) {
      ++ccc;
      minnS = min(minnS, shu[i].y);
      maxnS = max(maxnS, shu[i].y);
    }
  }
  if (ccc == 4) return 1;
  for (int i = 1; i <= cou; ++i)
    if (heng[i].y > minnH && heng[i].y < maxnH && heng[i].y >= D &&
        heng[i].y <= U && LMax[heng[i].pos] <= L && RMax[heng[i].pos] >= R) {
      que.push(Node(L, D, R, heng[i].y));
      que.push(Node(L, heng[i].y, R, U));
      return 1;
    }
  for (int i = 1; i <= cou; ++i)
    if (shu[i].y > minnS && shu[i].y < maxnS && shu[i].y >= L &&
        shu[i].y <= R && DMax[shu[i].pos] <= D && UMax[shu[i].pos] >= U) {
      que.push(Node(L, D, shu[i].y, U));
      que.push(Node(shu[i].y, D, R, U));
      return 1;
    }
  return 0;
}
bool SolveAll() {
  que.push(Node(0, 0, INF, INF));
  while (!que.empty()) {
    Node tmp = que.front();
    que.pop();
    if (!Solve1(tmp.L, tmp.D, tmp.R, tmp.U)) return 0;
  }
  return 1;
}
int main() {
  int n;
  int a, b, c, d;
  scanf("%d", &n);
  for (int i = 1; i <= n; ++i) {
    scanf("%d %d %d %d", &a, &b, &c, &d);
    ++cou;
    heng[cou] = Line(a, c, b, cou);
    shu[cou] = Line(b, d, a, cou);
    ++cou;
    heng[cou] = Line(a, c, d, cou);
    shu[cou] = Line(b, d, c, cou);
    uni_x[++cou_x] = a;
    uni_x[++cou_x] = c;
    uni_y[++cou_y] = b;
    uni_y[++cou_y] = d;
  }
  sort(uni_x + 1, uni_x + cou_x + 1);
  cou_x = unique(uni_x + 1, uni_x + cou_x + 1) - uni_x - 1;
  sort(uni_y + 1, uni_y + cou_y + 1);
  cou_y = unique(uni_y + 1, uni_y + cou_y + 1) - uni_y - 1;
  for (int i = 1; i <= cou; ++i) {
    heng[i].L = Unique(uni_x, cou_x, heng[i].L);
    heng[i].R = Unique(uni_x, cou_x, heng[i].R);
    heng[i].y = Unique(uni_y, cou_y, heng[i].y);
    shu[i].L = Unique(uni_y, cou_y, shu[i].L);
    shu[i].R = Unique(uni_y, cou_y, shu[i].R);
    shu[i].y = Unique(uni_x, cou_x, shu[i].y);
    if (i & 1)
      dian[i] = pair<double, double>(heng[i].L + 0.5, heng[i].y + 0.5);
    else
      dian[i] = dian[i - 1];
  }
  GetData(heng, shu, LMax, RMax);
  GetData(shu, heng, DMax, UMax);
  sort(heng + 1, heng + cou + 1, cmp3);
  sort(shu + 1, shu + cou + 1, cmp3);
  if (SolveAll())
    printf("YES\n");
  else
    printf("NO\n");
  return 0;
}
