#include <bits/stdc++.h>   using namespace std;   const long long int MAX = 100000;   vector<long long int> great[MAX + 1];   vector<long long int> small[MAX + 1];   vector<long long int> v[MAX + 1];   bool gactive[MAX + 1] = {false};   set<long long int> sactive;   long long int sz[MAX + 1] = {0};   struct moves {     long long int from, to, kind;   };   bool in(long long int x, vector<long long int>& p) {     if (lower_bound(p.begin(), p.end(), x) != p.end()) {       return (*lower_bound(p.begin(), p.end(), x) == x);     }     return false;   }   void solve() {     long long int n, m;     cin >> n >> m;     long long int tot = 0;     vector<pair<long long int, long long int>> szv(n + 1);     szv[0] = {0, 0};     for (long long int j = 1; j <= n; j++) {       long long int s;       cin >> s;       tot += s;       sz[j] = s;       szv[j] = {s, j};       for (long long int i = 0; i < s; i++) {         long long int c;         cin >> c;         v[j].push_back(c);       }     }     sort(szv.begin(), szv.end());     vector<long long int> gf(n + 1);     long long int sum = 0;     for (long long int j = 1; j <= n; j++) {       if ((tot / n) * (n - j + 1) == tot - sum) {         gf[j] = tot / n;       } else {         gf[j] = (tot + n - 1) / n;       }       sum += gf[j];     }     vector<long long int> should(n + 1);     for (long long int j = 1; j <= n; j++) {       should[szv[j].second] = gf[n - j + 1];     }     for (long long int j = 1; j <= n; j++) {       if (sz[j] > should[j]) {         gactive[j] = true;         for (auto i : v[j]) {           great[i].push_back(j);         }       } else if (sz[j] < should[j]) {         sactive.insert(j);         for (auto i : v[j]) {           small[i].push_back(j);         }       }     }     vector<moves> out;     for (long long int j = 1; j <= m; j++) {       if (((long long int)great[j].size()) == 0) continue;       long long int m1 = great[j].size(), m2 = small[j].size();       long long int ptr1 = 0, ptr2 = 0;       while (true) {         if (ptr1 == m1) break;         if (gactive[great[j][ptr1]]) break;         ptr1++;       }       if (ptr1 == m1) continue;       set<long long int> todel;       for (auto it : sactive) {         if (in(it, small[j]))           continue;         else {           sz[great[j][ptr1]]--;           sz[it]++;           {             struct moves q;             q.from = great[j][ptr1];             q.to = it;             q.kind = j;             out.push_back(q);           }           if (sz[great[j][ptr1]] <= should[great[j][ptr1]])             gactive[great[j][ptr1]] = false;           if (sz[it] >= should[it]) todel.insert(it);           ptr1++;           while (true) {             if (ptr1 == m1) break;             if (gactive[great[j][ptr1]]) break;             ptr1++;           }           if (ptr1 == m1) break;         }       }       for (auto it : todel) sactive.erase(it);     }     cout << (long long int)out.size() <<   n ;     for (auto q : out) {       cout << q.from <<     << q.to <<     << q.kind <<   n ;     }     return;   }   signed main() {     ios::sync_with_stdio(0);     cin.tie(NULL);     cout.tie(NULL);     long long int t;     t = 1;     while (t--) {       solve();     }     return 0;   }