#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;
}
