#pragma GCC optimize("O3") #include #include #include #include #include #include #include using namespace std; #define rep(i,a,b) for(int i=(a); i<(b); ++i) #define all(x) x.begin(),x.end() #define sz(x) int(x.size()) typedef long long ll; typedef unsigned long long ull; typedef vector vi; typedef vector vvi; // to quickly check if element exists, we use bitset const int N = 50000, B = 1000; typedef bitset bs; bs vis[N]; int main(){ cin.tie(NULL),cin.sync_with_stdio(false); int n; cin >> n; vvi a; vi inds, coords, tmp; rep(i,0,n){ int k; cin >> k; vi v(k); for(auto& c : v) cin >> c; if (k<2) continue; a.push_back(v); inds.push_back(i); for(auto c : v) tmp.push_back(c); } n = sz(a); sort(all(tmp)); rep(i,0,sz(tmp)-1) if ((!i or tmp[i-1] != tmp[i]) and tmp[i] == tmp[i+1]){ coords.push_back(tmp[i]); } assert(coords.size()<=N); rep(i,0,n) { rep(j,0,sz(a[i])){ auto it = lower_bound(all(coords), a[i][j]); if (it != end(coords) and *it == a[i][j]) { a[i][j] = it - begin(coords); vis[i][a[i][j]] = 1; }else{ a[i][j] = a[i].back(); a[i].pop_back(); --j; } } sort(all(a[i])); } vi ord(n); iota(all(ord),0); stable_sort(all(ord),[&](int i, int j){ return sz(a[i]) < sz(a[j]); }); rep(ii,0,n) if (sz(a[ord[ii]])>1) rep(jj,max(ii+1,n-B-1),n){ int i = ord[ii], j = ord[jj]; int frst = -1; for(auto v : a[i]) { if (vis[j][v]){ if (frst<0) frst = v; else{ // solution found! cerr << "FIRST\n"; cout << coords[frst] << ' ' << coords[v] << ' ' << inds[i]+1 << ' ' << inds[j]+1 << '\n'; exit(0); } } } } typedef unsigned short us; vector> pairs; pairs.reserve((51000/B)*51000); rep(ii,0,n-B){ int i = ord[ii]; rep(j,0,sz(a[i])) rep(k,j+1,sz(a[i])){ pairs.push_back({ (us) a[i][j], (us) a[i][k], (us) i}); } } sort(all(pairs)); rep(i,0,sz(pairs)-1){ if (pairs[i][0] == pairs[i+1][0] and pairs[i][1] == pairs[i+1][1]){ cerr << "SECOND\n"; cout << coords[pairs[i][0]] << ' ' << coords[pairs[i][1]] << ' ' << inds[pairs[i][2]]+1 << ' ' << inds[pairs[i+1][2]]+1 << '\n'; exit(0); } } cout << "impossible\n"; }