import sys
input = sys.stdin.buffer.readline
sys.setrecursionlimit(10 ** 7)


class UF_tree:
    def __init__(self, n):
        self.root = [-1] * (n + 1)
        self.rank = [0] * (n + 1)

    def find(self, x):
        if self.root[x] < 0:
            return x
        self.root[x] = self.find(self.root[x])
        return self.root[x]

    def isSame(self, x, y):
        return self.find(x) == self.find(y)

    def unite(self, x, y):
        x = self.find(x)
        y = self.find(y)
        if x == y:
            return False
        if self.rank[x] < self.rank[y]:
            self.root[y] += self.root[x]
            self.root[x] = y
        else:
            self.root[x] += self.root[y]
            self.root[y] = x
            if self.rank[x] == self.rank[y]:
                self.rank[x] += 1
        return True

    def size(self, x):
        return -self.root[self.find(x)]


def touch(x, y, xx, yy):
    if x == xx:
        return True
    if y == yy:
        return True
    if x == yy:
        return True
    if y == xx:
        return True
    return False


N = int(input())
match = tuple(tuple(map(int, input().split())) for _ in range(N))
uf = UF_tree(N)
G = [[] for _ in range(N)]
cycle = 0
for i in range(N):
    r, c, rr, cc = match[i]
    for j in range(i+1, N):
        rrr, ccc, rrrr, cccc = match[j]
        if touch((r, c), (rr, cc), (rrr, ccc), (rrrr, cccc)):
            G[i].append(j)
            uf.unite(i, j)

leader = {uf.find(i) for i in range(N)}
group = {i: [] for i in leader}
for i in range(N):
    group[uf.find(i)].append(i)

ok = True
for g in group.values():
    edge = 0
    for i in g:
        edge += len(G[i])
    if edge > len(g):
        ok = False

if ok:
    print("YES")
else:
    print("NO")