#include <bits/stdc++.h>
#pragma GCC optimize("Ofast")
using namespace std;
template <typename T1, typename T2>
inline bool upmax(T1& a, T2 b) {
  return (a < b ? (a = b, true) : false);
}
template <typename T1, typename T2>
inline bool upmin(T1& a, T2 b) {
  return (b < a ? (a = b, true) : false);
}
const int maxn = (int)1e5 + 5;
const int maxlog = 21;
const int base = (int)1e9 + 7;
const long double eps = (long double)1e-9;
const long double PI = acos(-1.);
const long long llinf = 1e18;
const int inf = 2e9;
struct node {
  int cnt;
  node *l, *r;
  node() {
    cnt = 0;
    l = 0;
    r = 0;
  }
};
int getcnt(node* v) {
  if (!v) return 0;
  return v->cnt;
}
void upd(node* v) { v->cnt = getcnt(v->l) + getcnt(v->r); }
void add(node* v, int tl, int tr, int pos, int x) {
  if (tl == tr) {
    v->cnt += x;
    assert(v->cnt == 0 || v->cnt == 1);
    return;
  }
  int tm = (tl + tr) >> 1;
  if (pos <= tm) {
    if ((v->l) == 0) {
      v->l = new node();
    }
    add(v->l, tl, tm, pos, x);
  } else {
    if ((v->r) == 0) {
      v->r = new node();
    }
    add(v->r, tm + 1, tr, pos, x);
  }
  upd(v);
}
node* getleft(node* v) {
  if (!v) return 0;
  return v->l;
}
node* getright(node* v) {
  if (!v) return 0;
  return v->r;
}
int diff(node* v1, node* v2, int tl, int tr) {
  assert(getcnt(v1) != getcnt(v2));
  if (tl == tr) {
    assert(getcnt(v2) != 0);
    return tl;
  }
  int tm = (tl + tr) >> 1;
  if (getcnt(getleft(v1)) < getcnt(getleft(v2))) {
    return diff(getleft(v1), getleft(v2), tl, tm);
  } else {
    return diff(getright(v1), getright(v2), tm + 1, tr);
  }
}
node* root[maxn];
void gen() {
  ofstream cout("input.txt");
  int n = rand() % 10 + 1, m = rand() % 10 + 1;
  cout << n << ' ' << m << endl;
  for (int i = 0; i < n; i++) {
    int x = rand() % (m + 1);
    set<int> second;
    for (int j = 0; j < x; j++) second.insert(rand() % m + 1);
    cout << second.size() << ' ';
    for (int x : second) cout << x << ' ';
    cout << endl;
  }
}
int main() {
  srand(time(0));
  int n, m;
  cin >> n >> m;
  for (int i = 0; i < n; i++) root[i] = new node();
  if (n == 1) {
    cout << 0 << endl;
    return 0;
  }
  set<pair<int, int> > q;
  for (int i = 0; i < n; i++) {
    int x;
    cin >> x;
    q.insert(make_pair(x, i));
    while (x--) {
      int y;
      cin >> y;
      y--;
      add(root[i], 0, m - 1, y, +1);
    }
  }
  vector<tuple<int, int, int> > ans;
  while (1) {
    auto i = q.begin()->second;
    auto j = (--q.end())->second;
    int s1 = q.begin()->first;
    int s2 = (--q.end())->first;
    q.erase(q.begin());
    q.erase(--q.end());
    if (s2 - s1 <= 1) {
      break;
    }
    int pos = diff(root[i], root[j], 0, m - 1);
    ans.push_back(make_tuple(j + 1, i + 1, pos + 1));
    add(root[i], 0, m - 1, pos, +1);
    add(root[j], 0, m - 1, pos, -1);
    q.insert(make_pair(s1 + 1, i));
    q.insert(make_pair(s2 - 1, j));
  }
  cout << ans.size() << "\n";
  for (int i = 0; i < ans.size(); i++) {
    int a, b, c;
    tie(a, b, c) = ans[i];
    cout << a << ' ' << b << ' ' << c << "\n";
  }
  return 0;
}
