#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1e5 + 179;
int n, m, ind[MAXN], buf[MAXN], sizes[MAXN], bufsz;
set<int> g[MAXN];
vector<tuple<int, int, int> > ans;
void insert(int i1, int i2, int cnt) {
  bufsz = 0;
  for (int col : g[i1]) {
    if (!cnt) {
      break;
    }
    if (!g[i2].count(col)) {
      --cnt;
      buf[bufsz++] = col;
      ans.push_back({i1 + 1, i2 + 1, col});
    }
  }
  assert(cnt == 0);
  for (int i = 0; i < bufsz; ++i) {
    g[i2].insert(buf[i]);
    g[i1].erase(buf[i]);
  }
}
void solve() {
  cin >> n >> m;
  int total = 0, sz, x;
  for (int i = 0; i < n; ++i) {
    cin >> sz;
    total += sz;
    for (int j = 0; j < sz; ++j) {
      cin >> x;
      g[i].insert(x);
    }
  }
  int k = total / n, ptr = 0;
  x = total % n;
  iota(ind, ind + n, 0);
  fill_n(sizes, n, k);
  fill_n(sizes, x, k + 1);
  sort(ind, ind + n, [](int x, int y) { return g[x].size() > g[y].size(); });
  for (int i = 0; i < n; ++i) {
    int i1 = ind[i];
    while ((int)g[i1].size() > sizes[i]) {
      for (; ptr < n && (int)g[ind[ptr]].size() >= sizes[ptr]; ++ptr)
        ;
      if (ptr == n) {
        break;
      }
      int c1 = (int)g[i1].size() - sizes[i];
      int c2 = sizes[ptr] - (int)g[ind[ptr]].size();
      insert(i1, ind[ptr], min(c1, c2));
    }
  }
  cout << ans.size() << endl;
  for (const auto& x : ans) {
    cout << (get<0>(x)) << " " << (get<1>(x)) << " " << (get<2>(x)) << '\n';
  }
}
signed main() {
  ios_base::sync_with_stdio(false);
  cout.tie(0);
  cin.tie(0);
  solve();
  return 0;
}
