#include <bits/stdc++.h>
using namespace std;
#pragma GCC diagnostic ignored "-Wmissing-declarations"
inline int safe_mul(const int x, const int y)
    __attribute__((warn_unused_result));
int const maxn = 100003;
set<int> used[maxn];
int main() {
  ios_base::sync_with_stdio(false);
  int n, m;
  cin >> n >> m;
  vector<pair<int, int>> nums;
  for (int i = 0; i < n; ++i) {
    int s;
    cin >> s;
    for (int j = 0; j < s; ++j) {
      int x;
      cin >> x;
      used[i].insert(x);
    }
    nums.emplace_back(s, i);
  }
  sort(nums.begin(), nums.end());
  long long acnt = 0;
  for (const auto& p : nums) acnt += p.first;
  vector<int> need(n);
  for (int i = 0; i < n; ++i) {
    need[i] = acnt / n + (n - i <= acnt % n);
  }
  int l = 0;
  int r = n - 1;
  vector<tuple<int, int, int>> result;
  for (;;) {
    while (l < r && nums[l].first == need[l]) ++l;
    while (r > l && nums[r].first == need[r]) --r;
    if (l >= r) break;
    vector<int> add;
    int can = min(need[l] - nums[l].first, nums[r].first - need[r]);
    for (int x : used[nums[r].second]) {
      if (used[nums[l].second].find(x) == used[nums[l].second].end()) {
        add.push_back(x);
        if (add.size() > can) break;
      }
    }
    for (int idx : add) {
      result.emplace_back(nums[r].second + 1, nums[l].second + 1, idx);
      used[nums[l].second].insert(idx);
      used[nums[r].second].erase(idx);
      --nums[r].first;
      ++nums[l].first;
      if (nums[l].first == need[l] || nums[r].first == need[r]) {
        break;
      }
    }
  }
  cout << result.size() << endl;
  for (const auto& t : result)
    cout << get<0>(t) << ' ' << get<1>(t) << ' ' << get<2>(t) << '\n';
}
