#include <bits/stdc++.h>
using namespace std;
struct box {
  int id, to;
  set<int> items;
};
struct offert {
  int type, where;
  bool operator<(const offert &x) const {
    return (type == x.type) ? (where < x.where) : (type < x.type);
  }
};
struct moves {
  int x, y, z;
};
int main() {
  ios_base::sync_with_stdio(0), cin.tie(0);
  int n, m;
  cin >> n >> m;
  int s = 0;
  vector<box> a(n);
  for (auto &i : a) {
    i.id = &i - &a[0];
    int k, x;
    cin >> k;
    s += k;
    while (k--) {
      cin >> x;
      i.items.insert(x);
    }
  }
  vector<int> ord(n);
  iota(ord.begin(), ord.end(), 0);
  sort(ord.begin(), ord.end(), [&](const int &x, const int &y) {
    return a[x].items.size() < a[y].items.size();
  });
  int l = s / n, r = (s + n - 1) / n, cnt = s - l * n;
  set<offert> q, can;
  for (auto &x : ord) {
    auto &i = a[x];
    i.to = l + (n - (&x - &ord[0]) <= cnt);
    if (i.items.size() > i.to)
      for (auto j : i.items) q.insert({j, i.id});
  }
  auto try_add = [&](set<int> &t, int j) {
    auto nxt = q.upper_bound({j, 1 << 30});
    auto prv = q.lower_bound({j, -1});
    if (prv == q.begin())
      prv = q.end();
    else
      prv = prev(prv);
    if (prv != q.end() && t.find(prv->type) == t.end()) {
      can.insert(*prv);
      q.erase(prv);
    }
    if (nxt != q.end() && t.find(nxt->type) == t.end()) {
      can.insert(*nxt);
      q.erase(nxt);
    }
  };
  vector<moves> op;
  for (auto &i : a)
    if (i.items.size() < i.to) {
      can.clear();
      for (auto j : i.items) try_add(i.items, j);
      if (i.items.empty()) {
        can.insert(*q.begin());
        q.erase(q.begin());
      }
      for (; i.items.size() < i.to;) {
        auto it = can.begin();
        while (i.items.find(it->type) != i.items.end()) {
          q.insert(*it);
          can.erase(it);
          it = can.begin();
        }
        op.push_back({it->where, i.id, it->type});
        i.items.insert(it->type);
        auto val = *it;
        can.erase(it);
        a[val.where].items.erase(val.type);
        if (a[val.where].items.size() == a[val.where].to) {
          for (auto z : a[val.where].items) {
            q.erase({z, val.where});
            can.erase({z, val.where});
          }
          for (auto z : a[val.where].items) try_add(i.items, z);
        }
        try_add(i.items, val.type);
      }
      for (auto o : can) q.insert(o);
    }
  cout << op.size() << "\n";
  for (auto &i : op) cout << i.x + 1 << " " << i.y + 1 << " " << i.z << "\n";
  return 0;
}
