#include using namespace std; using u64 = unsigned long long; constexpr size_t max_b = 1'000'000; constexpr size_t max_w = (max_b + 64 - 1) / 64; struct Bitset; auto seen = set>(); struct Bitset { array have; basic_string elems; void set(int i) { have[i / 64] |= u64(1) << i % 64; elems.push_back(i); } bool has(int i) { return have[i / 64] >> i % 64 & 1; } friend bool test(Bitset &a, Bitset &b) { auto [it, placed] = seen.emplace(pair{&a, &b}); if (!placed) return false; if (a.elems.size() <= 1000) { for (int x : a.elems) { if (!b.has(x)) { cerr << "bigger doesn't have " << x << '\n'; return true; } } return false; } for (int w = 0; w != max_w; ++w) { if (a.have[w] & ~b.have[w]) return true; } return false; } }; int main() { cin.tie(nullptr)->sync_with_stdio(false); int n, m; cin >> n >> m; auto likers_of = vector>(m); auto hashes = vector(n); auto contribs = vector(m); auto rng = mt19937_64(chrono::steady_clock::now().time_since_epoch().count()); for (int i = 0; i != m; ++i) { contribs[i] = rng(); } auto sizes = vector(n); auto have = vector(n); for (int i = 0; i != n; ++i) { int &k = sizes[i]; cin >> k; for (int kk = 0; kk != k; ++kk) { int j; cin >> j; --j; hashes[i] ^= contribs[j]; likers_of[j].push_back(i); have[i].set(j); } } for (int j = 0; j != m; ++j) { sort(likers_of[j].begin(), likers_of[j].end(), [&](int i0, int i1) { return sizes[i0] < sizes[i1]; }); for (int p = 0; p + 1 < likers_of[j].size(); ++p) { int i0 = likers_of[j][p]; int i1 = likers_of[j][p + 1]; if (hashes[i0] == hashes[i1]) continue; if (sizes[i0] == sizes[i1] || test(have[i0], have[i1])) { cout << "YES\n"; cout << i0 + 1 << ' ' << i1 + 1 << '\n'; return 0; } } } cout << "NO\n"; }