#include <bits/stdc++.h>
using namespace std;
const int INF = 1000000001;
int main(){
int N;
cin >> N; // 输入箱子的数量
vector h(N), w(N), d(N); // 分别存储箱子的高度、宽度和深度
for (int i = 0; i < N; i++){
cin >> h[i] >> w[i] >> d[i]; // 输入每个箱子的高度、宽度和深度
}
map<int, vector<pair<int, int>>> mp; // 创建一个map,键为箱子的高度/宽度/深度,值为一个向量,存储与该高度/宽度/深度对应的所有箱子的宽度/深度
for (int i = 0; i < N; i++){
mp[h[i]].push_back(make_pair(w[i], d[i])); // 将每个箱子的宽度和深度添加到与该箱子高度对应的向量中
mp[h[i]].push_back(make_pair(d[i], w[i])); // 将每个箱子的深度和宽度添加到与该箱子高度对应的向量中
mp[w[i]].push_back(make_pair(h[i], d[i])); // 将每个箱子的高度和深度添加到与该箱子宽度对应的向量中
mp[w[i]].push_back(make_pair(d[i], h[i])); // 将每个箱子的深度和高度添加到与该箱子宽度对应的向量中
mp[d[i]].push_back(make_pair(h[i], w[i])); // 将每个箱子的高度和宽度添加到与该箱子深度对应的向量中
mp[d[i]].push_back(make_pair(w[i], h[i])); // 将每个箱子的宽度和高度添加到与该箱子深度对应的向量中
}
map<int, int> mp2; // 创建一个map,键为箱子的宽度/深度,值为箱子的高度
mp2[0] = INF; // 将键为0的值设为无穷大
mp2[INF] = 0; // 将键为无穷大的值设为0
bool ok = false; // 判断是否存在合法的箱子堆叠方式
for (auto P : mp){ // 遍历mp中的每个键值对
int cnt = P.second.size(); // 获取该键对应的向量的大小
for (int i = 0; i < cnt; i++){ // 遍历该向量中的每个元素
int x = P.second[i].first; // 获取箱子的宽度/深度
int y = P.second[i].second; // 获取箱子的深度/宽度
auto itr = mp2.lower_bound(x); // 找到第一个大于等于x的键
itr--; // 将迭代器前移一位,得到小于x的键
if ((*itr).second < y){ // 如果该键对应的值小于y,则存在合法的箱子堆叠方式
ok = true;
}
}
for (int i = 0; i < cnt; i++){ // 遍历该向量中的每个元素
int x = P.second[i].first; // 获取箱子的宽度/深度
int y = P.second[i].second; // 获取箱子的深度/宽度
if (mp2.count(x) == 0){ // 如果mp2中不存在键为x的元素
auto itr = prev(mp2.lower_bound(x)); // 找到第一个小于x的键
int a = (*itr).second; // 获取该键对应的值
mp2[x] = a; // 添加一个新键值对,键为x,值为a
}
while (true){
auto itr = mp2.lower_bound(x); // 找到第一个大于等于x的键
if ((*itr).second > y){ // 如果该键对应的值大于y
mp2.erase(itr); // 删除该键值对
} else {
break;
}
}
mp2[x] = y; // 将键为x的值设为y
auto itr = prev(mp2.lower_bound(x)); // 找到第一个小于x的键
if ((*itr).second <= y){ // 如果该键对应的值小于等于y
mp2.erase(x); // 删除键为x的键值对
}
}
}
if (ok){ // 如果存在合法的箱子堆叠方式
cout << "Yes" << endl;
} else {
cout << "No" << endl;
}