const SIZE: usize = 1e4 as usize; struct UnionFind { n: usize, parents: Vec, } impl UnionFind { fn new(n: usize) -> Self { UnionFind { n: n, parents: (0..n).collect(), } } fn equiv(&mut self, a: usize, b: usize) -> bool { self.find(a) == self.find(b) } fn unite(&mut self, a: usize, b: usize) { if self.equiv(a, b) { return; } let (a, b) = (a.min(b), a.max(b)); let x = self.parents[a]; let y = self.parents[b]; self.parents[y] = self.parents[x]; } fn find(&mut self, a: usize) -> usize { if self.parents[a] == a { return a; } let p = self.find(self.parents[a]); self.parents[a] = p; p } } fn main() { let mut n = String::new(); std::io::stdin().read_line(&mut n).ok(); let n: usize = n.trim().parse().unwrap(); let items = (0..n).map(|_| { let mut temp = String::new(); std::io::stdin().read_line(&mut temp).ok(); let temp: Vec = temp.trim().split_whitespace().map(|s| s.parse().unwrap()).collect(); (temp[0].min(temp[2]), temp[1].min(temp[3]), temp[0].max(temp[2]), temp[1].max(temp[3])) }) .collect::>(); let mut uf = UnionFind::new(SIZE); let mut size = vec![1usize; SIZE]; let mut linecnt = vec![0usize; SIZE]; for &(r0, c0, r1, c1) in items.iter() { let idx0 = (r0-1) * 100 + (c0-1); let idx1 = (r1-1) * 100 + (c1-1); let p0 = uf.find(idx0); let p1 = uf.find(idx1); if p0 == p1 { linecnt[p0] += 1; continue; } uf.unite(p0, p1); let p = uf.find(p0); if p == p0 { size[p0] += size[p1]; size[p1] = 0; linecnt[p0] += linecnt[p1]+1; linecnt[p1] = 0; } else { size[p1] += size[p0]; size[p0] = 0; linecnt[p1] += linecnt[p0]+1; linecnt[p0] = 0; } } if (0..SIZE).any(|i| size[i] < linecnt[i]) { println!("NO"); } else { println!("YES"); } }