#include <cstdio>
#include <vector>
#include <set>
#include <algorithm>
using namespace std;

const int INF = int(1.05e9);

inline unsigned int getHighestOneBit(unsigned int x) {
	/*
	x |= (x >> 1);
	x |= (x >> 2);
	x |= (x >> 4);
	x |= (x >> 8);
	x |= (x >> 16);
	return x & ~(x >> 1);
	*/
	return 1<<(31 - __builtin_clz(x));
}

class SegMax {
	int N;
	vector<int> maxi;
	inline void doit(int k, int x) {maxi[k] = max(maxi[k], x);}
public:
	SegMax(int n) : N(n == 1 ? 1 : 1<<(32 - __builtin_clz(n - 1))), maxi(2*N, 0) {}
	int query(int k) {
		int ans = 0;
		for (k+=N;k>0;k>>=1) ans = max(ans, maxi[k]);
		return ans;
	}

	void fill(int s, int t, int x) {
		for (int idx;0<s && s+(s&-s)<=t && (idx=(N+s)/(s&-s)); s+=s&-s) doit(idx, x);
		for (int idx;s<t && (idx=(N+t)/(t&-t)-1); t-=t&-t) doit(idx, x);
	}
};

class SegRMQ {
	int N;
	vector<pair<int, bool> > datas;//(mini, uniform)
	inline void update(int k) {
		datas[k].first = min(datas[2*k].first, datas[2*k+1].first);
	}
	inline void prop(int k) {
		if (datas[k].second) {
			datas[2*k] = datas[2*k+1] = datas[k];
			datas[k].second = false;
		}
	}
	inline int getWidth(int i) {
		return N / getHighestOneBit(i);
	}
public:
	SegRMQ(const vector<int>& ns) {
		N = ns.size() == 1 ? 1 : 1<<(32 - __builtin_clz(int(ns.size())-1));
		datas.assign(2*N, make_pair(INF, false));
		for (int i = 0; i < int(ns.size()); ++i) {
			datas[i+N].first = ns[i];
		}
		for (int i = N - 1 ; i > 0; --i) update(i);
	}

	int getMin(int L, int R) {
		static int inds[128], len;
		len = 0;
		if(L)for(int k=(N+L)/(L&-L);k>>=1;) inds[len++] = k;
		if(R)for(int k=(N+R)/(R&-R)-1;k>>=1;) inds[len++] = k;
		sort(inds, inds+len);
		len = unique(inds, inds+len) - inds;
		for(int i=0; i<len; ++i) prop(inds[i]);
		int ans = INF;
		for (int idx;0<L && L+(L&-L)<=R && (idx=(N+L)/(L&-L)); L+=L&-L) ans = min(ans, datas[idx].first);
		for (int idx;L<R && (idx=(N+R)/(R&-R)-1); R-=R&-R) ans = min(ans, datas[idx].first);
		return ans;
	}

	void fill(int L, int R, int x) {
		static int inds[128], len;
		len = 0;
		if(L)for(int k=(N+L)/(L&-L);k>>=1;) inds[len++] = k;
		if(R)for(int k=(N+R)/(R&-R)-1;k>>=1;) inds[len++] = k;
		sort(inds, inds+len);
		len = unique(inds, inds+len) - inds;
		for(int i=0; i<len; ++i) prop(inds[i]);
		for (int idx;0<L && L+(L&-L)<=R && (idx=(N+L)/(L&-L)); L+=L&-L) datas[idx] = make_pair(x,true);
		for (int idx;L<R && (idx=(N+R)/(R&-R)-1); R-=R&-R) datas[idx] = make_pair(x,true);
		for(int i=len; --i;) update(inds[i]);
	}
};

const int MAX_N = int(5e4);
int as[MAX_N], bs[MAX_N], ys[MAX_N], ns[2*MAX_N], ts[MAX_N];

int main() {
	int n; scanf("%d", &n);
	int L = 0;
	for (int i = 0; i < n; ++i) {
		scanf("%d%d%d%d", ts+i, as+i, bs+i, ys+i);
		++bs[i];
		ns[L++] = as[i];
		ns[L++] = bs[i];
	}
	sort(ns, ns + L);
	L = unique(ns, ns+L) - ns;
	for (int i = 0; i < n; ++i) {
		as[i] = lower_bound(ns, ns+L, as[i]) - ns;
		bs[i] = lower_bound(ns, ns+L, bs[i]) - ns;
	}

	SegMax seg(L);
	set<int> ids;
	vector<int> xs(L);
	for (int i = 0; i < L; ++i) {
		ids.insert(i);
	}
	for (int i = 0; i < n; ++i) {
		if (ts[i] == 0) {
			seg.fill(as[i], bs[i], ys[i]);
		}
		else {
			for (set<int>::iterator itr = ids.lower_bound(as[i]); itr != ids.end() && *itr < bs[i]; ids.erase(itr++)) {
				xs[*itr] = seg.query(*itr);
			}
		}
	}
	for (set<int>::iterator itr = ids.begin(); itr != ids.end(); ++itr) {
		xs[*itr] = seg.query(*itr);
	}
	SegRMQ rmq(xs);
	for (int i = 0; i < n; ++i) {
		if (ts[i] == 0 && rmq.getMin(as[i], bs[i]) != ys[i]) {
			puts("NO");
			return 0;
		}
		else if (ts[i] == 1) {
			rmq.fill(as[i], bs[i], ys[i]);
		}
	}
	puts("YES");

	return 0;
}

Measured memory_bytes: 8124