Filled with optimism, Hyunuk will host a conference about how great this new year will be!

The conference will have n lectures. Hyunuk has two candidate venues a and b. For each of the n lectures, the speaker specified two time intervals [sa_i, ea_i] (sa_i ≤ ea_i) and [sb_i, eb_i] (sb_i ≤ eb_i). If the conference is situated in venue a, the lecture will be held from sa_i to ea_i, and if the conference is situated in venue b, the lecture will be held from sb_i to eb_i. Hyunuk will choose one of these venues and all lectures will be held at that venue.

Two lectures are said to overlap if they share any point in time in common. Formally, a lecture held in interval [x, y] overlaps with a lecture held in interval [u, v] if and only if max(x, u) ≤ min(y, v).

We say that a participant can attend a subset s of the lectures if the lectures in s do not pairwise overlap (i.e. no two lectures overlap). Note that the possibility of attending may depend on whether Hyunuk selected venue a or venue b to hold the conference.

A subset of lectures s is said to be venue-sensitive if, for one of the venues, the participant can attend s, but for the other venue, the participant cannot attend s.

A venue-sensitive set is problematic for a participant who is interested in attending the lectures in s because the participant cannot be sure whether the lecture times will overlap. Hyunuk will be happy if and only if there are no venue-sensitive sets. Determine whether Hyunuk will be happy.

Input

The first line contains an integer n (1 ≤ n ≤ 100 000), the number of lectures held in the conference.

Each of the next n lines contains four integers sa_i, ea_i, sb_i, eb_i (1 ≤ sa_i, ea_i, sb_i, eb_i ≤ 10^9, sa_i ≤ ea_i, sb_i ≤ eb_i).

Output

Print "YES" if Hyunuk will be happy. Print "NO" otherwise.

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

Examples

Input


2
1 2 3 6
3 4 7 8


Output


YES


Input


3
1 3 2 4
4 5 6 7
3 4 5 5


Output


NO


Input


6
1 5 2 9
2 4 5 8
3 6 7 11
7 10 12 16
8 11 13 17
9 12 14 18


Output


YES

Note

In second example, lecture set \{1, 3\} is venue-sensitive. Because participant can't attend this lectures in venue a, but can attend in venue b.

In first and third example, venue-sensitive set does not exist.

import java.io.BufferedWriter;
import java.io.DataInputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.Comparator;
import java.util.PriorityQueue;

public class D {

	public static void main(String[] args) throws Exception {
		FastScanner sc = new FastScanner(System.in);
		FastPrinter out = new FastPrinter(System.out);
		D runner = new D();
		runner.run(sc, out);
		out.close();
	}

	public void run(FastScanner sc, FastPrinter out) throws Exception {
		int N = sc.nextInt();
		int[][] arr = new int[N][];
		int[] comp1 = new int[2 * N];
		int[] comp2 = new int[2 * N];
		for (int i = 0; i < N; i++) {
			// int aS = sc.nextInt();
			// int aE = sc.nextInt();
			// int bS = sc.nextInt();
			// int bE = sc.nextInt();
			arr[i] = sc.nextIntArray(4);
			comp1[i * 2] = arr[i][0];
			comp1[i * 2 + 1] = arr[i][1];
			comp2[i * 2] = arr[i][2];
			comp2[i * 2 + 1] = arr[i][3];
		}
		Arrays.sort(comp1);
		Arrays.sort(comp2);
		for (int i = 0; i < N; i++) {
			arr[i][0] = Arrays.binarySearch(comp1, arr[i][0]) + 1;
			arr[i][1] = Arrays.binarySearch(comp1, arr[i][1]) + 1;
			arr[i][2] = Arrays.binarySearch(comp2, arr[i][2]) + 1;
			arr[i][3] = Arrays.binarySearch(comp2, arr[i][3]) + 1;
		}
		for (int i = 0; i < N; i++) {
			int rand = (int) (Math.random() * N);
			int[] temp = arr[i];
			arr[i] = arr[rand];
			arr[rand] = temp;
		}
		Arrays.sort(arr, new Comparator<int[]>() {
			@Override
			public int compare(int[] a, int[] b) {
				return a[0] - b[0];
			}
		});
		// System.out.println(Arrays.deepToString(arr));
		PriorityQueue<int[]> pq = new PriorityQueue<>(new Comparator<int[]>() {
			@Override
			public int compare(int[] a, int[] b) {
				return a[1] - b[1];
			}
		});
		Seg seg = new Seg(2 * N + 1);
		for (int i = 0; i < N; i++) {
			int x = arr[i][0];
			while (!pq.isEmpty()) {
				int[] cur = pq.peek();
				if (cur[1] < x) {
					pq.poll();
					seg.update(cur[2], cur[3], 1);
				} else {
					break;
				}
			}
			int q = -seg.query(arr[i][2], arr[i][3]);
			if (q != pq.size()) {
				System.out.println("NO");
				return;
			}
			pq.add(arr[i]);
			seg.update(arr[i][2], arr[i][3], -1);
		}
		for (int i = 0; i < N; i++) {
			int rand = (int) (Math.random() * N);
			int[] temp = arr[i];
			arr[i] = arr[rand];
			arr[rand] = temp;
		}
		Arrays.sort(arr, new Comparator<int[]>() {
			@Override
			public int compare(int[] a, int[] b) {
				return a[2] - b[2];
			}
		});
		pq = new PriorityQueue<>(new Comparator<int[]>() {
			@Override
			public int compare(int[] a, int[] b) {
				return a[3] - b[3];
			}
		});
		seg = new Seg(2 * N + 1);
		for (int i = 0; i < N; i++) {
			int x = arr[i][2];
			while (!pq.isEmpty()) {
				int[] cur = pq.peek();
				if (cur[3] < x) {
					pq.poll();
					seg.update(cur[0], cur[1], 1);
				} else {
					break;
				}
			}
			int q = -seg.query(arr[i][0], arr[i][1]);
			if (q != pq.size()) {
				System.out.println("NO");
				return;
			}
			pq.add(arr[i]);
			seg.update(arr[i][0], arr[i][1], -1);
		}
		System.out.println("YES");
	}

	static class Seg {
		int[] arr, seg, lazy;
		int n;

		public Seg(int[] arr) {
			this.arr = arr;
			this.n = arr.length;
			seg = new int[4 * n];
			lazy = new int[4 * n];
			build(1, 1, n);
		}

		public Seg(int n) {
			this.n = n;
			seg = new int[4 * n];
			lazy = new int[4 * n];
		}

		private void build(int node, int l, int r) {
			if (l == r) {
				// CAREFUL! THIS ASSUMES THE ARRAY IS 0 INDEXED(which it probably is)
				seg[node] = arr[l - 1];
				return;
			}
			int mid = (l + r) / 2;
			build(node * 2, l, mid);
			build(node * 2 + 1, mid + 1, r);
			// change this
			seg[node] = Math.min(seg[node * 2], seg[node * 2 + 1]);

		}

		private int query(int a, int b) {
			return query(1, 1, n, a, b);
		}

		private int query(int node, int l, int r, int a, int b) {
			if (a <= l && r <= b) {
				return seg[node];
			}
			prop(node, l, r);
			int ans = Integer.MAX_VALUE;
			int mid = (l + r) / 2;
			if (a <= mid) {
				// change this
				ans = Math.min(ans, query(node * 2, l, mid, a, b));
			}
			if (b > mid) {
				// change this
				ans = Math.min(ans, query(node * 2 + 1, mid + 1, r, a, b));
			}
			return ans;
		}

		private void update(int a, int b, int x) {
			update(1, 1, n, a, b, x);
		}

		private void update(int node, int l, int r, int a, int b, int x) {
			if (a <= l && r <= b) {
				lazy[node] += x;
				// change this
				seg[node] += x;
				return;
			}
			prop(node, l, r);
			int mid = (l + r) / 2;
			if (a <= mid) {
				// change this
				update(node * 2, l, mid, a, b, x);
			}
			if (b > mid) {
				// change this
				update(node * 2 + 1, mid + 1, r, a, b, x);
			}
			// change this
			seg[node] = Math.min(seg[node * 2], seg[node * 2 + 1]);

		}

		private void prop(int node, int l, int r) {
			if (lazy[node] != 0) {
				int mid = (l + r) / 2;
				// change this
				seg[node * 2] += lazy[node];
				seg[node * 2 + 1] += lazy[node];
				lazy[node * 2] += lazy[node];
				lazy[node * 2 + 1] += lazy[node];
				lazy[node] = 0;
			}
		}

	}

	public void shuffle(int[] arr) {
		for (int i = 0; i < arr.length; i++) {
			int r = (int) (Math.random() * arr.length);
			if (i != r) {
				arr[i] ^= arr[r];
				arr[r] ^= arr[i];
				arr[i] ^= arr[r];
			}
		}
	}

	static class FastScanner {
		final private int BUFFER_SIZE = 1 << 10;
		private DataInputStream din;
		private byte[] buffer;
		private int bufferPointer, bytesRead;

		public FastScanner() {
			this(System.in);
		}

		public FastScanner(InputStream stream) {
			din = new DataInputStream(stream);
			buffer = new byte[BUFFER_SIZE];
			bufferPointer = bytesRead = 0;
		}

		public FastScanner(String fileName) throws IOException {
			Path p = Paths.get(fileName);
			buffer = Files.readAllBytes(p);
			bytesRead = buffer.length;
		}

		int[] nextIntArray(int N) throws IOException {
			int[] arr = new int[N];
			for (int i = 0; i < N; i++) {
				arr[i] = nextInt();
			}
			return arr;
		}

		String nextLine() throws IOException {
			int c = read();
			while (c != -1 && isEndline(c))
				c = read();
			if (c == -1) {
				return null;
			}
			StringBuilder res = new StringBuilder();
			do {
				if (c >= 0) {
					res.appendCodePoint(c);
				}
				c = read();
			} while (!isEndline(c));
			return res.toString();
		}

		boolean isEndline(int c) {
			return c == '\n' || c == '\r' || c == -1;
		}

		String next() throws Exception {
			int c = readOutSpaces();
			StringBuilder res = new StringBuilder();
			do {
				res.appendCodePoint(c);
				c = read();
			} while (!isSpaceChar(c));
			return res.toString();
		}

		boolean isSpaceChar(int c) {
			return c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == -1;
		}

		public int nextInt() throws IOException {
			int ret = 0;
			byte c = read();
			while (c <= ' ')
				c = read();
			boolean neg = (c == '-');
			if (neg) c = read();
			do {
				ret = ret * 10 + c - '0';
			} while ((c = read()) >= '0' && c <= '9');

			if (neg) return -ret;
			return ret;
		}

		public long nextLong() throws IOException {
			long ret = 0;
			byte c = read();
			while (c <= ' ')
				c = read();
			boolean neg = (c == '-');
			if (neg) c = read();
			do {
				ret = ret * 10 + c - '0';
			} while ((c = read()) >= '0' && c <= '9');
			if (neg) return -ret;
			return ret;
		}

		public double nextDouble() throws IOException {
			double ret = 0, div = 1;
			byte c = read();
			while (c <= ' ')
				c = read();
			boolean neg = (c == '-');
			if (neg) c = read();

			do {
				ret = ret * 10 + c - '0';
			} while ((c = read()) >= '0' && c <= '9');

			if (c == '.') {
				while ((c = read()) >= '0' && c <= '9') {
					ret += (c - '0') / (div *= 10);
				}
			}

			if (neg) return -ret;
			return ret;
		}

		private void fillBuffer() throws IOException {
			if (din == null) {
				bufferPointer = 0;
				bytesRead = -1;
			} else {
				bytesRead = din.read(buffer, bufferPointer = 0, BUFFER_SIZE);
			}
			if (bytesRead == -1) buffer[0] = -1;
		}

		private byte read() throws IOException {
			if (bufferPointer == bytesRead) fillBuffer();
			return buffer[bufferPointer++];
		}

		private int readOutSpaces() throws IOException {
			while (true) {
				if (bufferPointer == bytesRead) fillBuffer();
				int c = buffer[bufferPointer++];
				if (!isSpaceChar(c)) {
					return c;
				}
			}
		}

		public void close() throws IOException {
			if (din == null) return;
			din.close();
		}

		public int[][] readGraph(int N, int M, boolean zeroIndexed, boolean bidirectional) throws Exception {
			int[][] adj = new int[N][];
			int[] numNodes = new int[N];
			int[][] input = new int[M][2];
			for (int i = 0; i < M; i++) {
				int a = nextInt();
				int b = nextInt();
				if (zeroIndexed) {
					a--;
					b--;
				}
				input[i][0] = a;
				input[i][1] = b;
				numNodes[a]++;
				if (bidirectional) numNodes[b]++;
			}
			for (int i = 0; i < N; i++) {
				adj[i] = new int[numNodes[i]];
				numNodes[i] = 0;
			}
			for (int i = 0; i < M; i++) {
				int a = input[i][0];
				int b = input[i][1];
				adj[a][numNodes[a]++] = b;
				if (bidirectional) adj[b][numNodes[b]++] = a;
			}
			return adj;
		}

		public int[][][] readWeightedGraph(int N, int M, boolean zeroIndexed, boolean bidirectional) throws Exception {
			int[][][] adj = new int[N][][];
			int[] numNodes = new int[N];
			int[][] input = new int[M][3];
			for (int i = 0; i < M; i++) {
				int a = nextInt();
				int b = nextInt();
				if (zeroIndexed) {
					a--;
					b--;
				}
				int d = nextInt();
				input[i][0] = a;
				input[i][1] = b;
				input[i][2] = d;
				numNodes[a]++;
				if (bidirectional) numNodes[b]++;
			}
			for (int i = 0; i < N; i++) {
				adj[i] = new int[numNodes[i]][2];
				numNodes[i] = 0;
			}
			for (int i = 0; i < M; i++) {
				int a = input[i][0];
				int b = input[i][1];
				int d = input[i][2];
				adj[a][numNodes[a]][0] = b;
				adj[a][numNodes[a]][1] = d;
				numNodes[a]++;
				if (bidirectional) {
					adj[b][numNodes[b]][0] = a;
					adj[b][numNodes[b]][1] = d;
					numNodes[b]++;
				}
			}
			return adj;
		}
	}

	static class FastPrinter {
		static final char ENDL = '\n';
		StringBuilder buf;
		PrintWriter pw;

		public FastPrinter(OutputStream stream) {
			buf = new StringBuilder();
			pw = new PrintWriter(new BufferedWriter(new OutputStreamWriter(stream)));
		}

		public FastPrinter(String fileName) throws Exception {
			buf = new StringBuilder();
			pw = new PrintWriter(new BufferedWriter(new FileWriter(fileName)));
		}

		public FastPrinter(StringBuilder buf) {
			this.buf = buf;
		}

		public void print(int a) {
			buf.append(a);
		}

		public void print(long a) {
			buf.append(a);
		}

		public void print(char a) {
			buf.append(a);
		}

		public void print(char[] a) {
			buf.append(a);
		}

		public void print(double a) {
			buf.append(a);
		}

		public void print(String a) {
			buf.append(a);
		}

		public void print(Object a) {
			buf.append(a.toString());
		}

		public void println() {
			buf.append(ENDL);
		}

		public void println(int a) {
			buf.append(a);
			buf.append(ENDL);
		}

		public void println(long a) {
			buf.append(a);
			buf.append(ENDL);
		}

		public void println(char a) {
			buf.append(a);
			buf.append(ENDL);
		}

		public void println(char[] a) {
			buf.append(a);
			buf.append(ENDL);
		}

		public void println(double a) {
			buf.append(a);
			buf.append(ENDL);
		}

		public void println(String a) {
			buf.append(a);
			buf.append(ENDL);
		}

		public void println(Object a) {
			buf.append(a.toString());
			buf.append(ENDL);
		}

		public void printf(String format, Object... args) {
			buf.append(String.format(format, args));
		}

		public void close() {
			pw.print(buf);
			pw.close();
		}

		public void flush() {
			pw.print(buf);
			pw.flush();
			buf.setLength(0);
		}

	}

}