#include <bits/stdc++.h>
using namespace std;
int n, m;
const int sz = 1 << 13;
vector<int> gos[5001];
int rev[5001];
template <class T>
class Dinic {
  struct _edge {
    int x, y;
    T c, rc;
    _edge(int x, int y, T c, T rc) : x(x), y(y), c(c), rc(rc) {}
  };
  int s, e;
  int n;
  vector<T> nowFlow;
  vector<vector<int>> edge;
  vector<_edge> es;
  vector<int> dist;
  vector<int> it;
  T inf;
  int bfs() {
    for (int i = 0; i < n; ++i) dist[i] = -1;
    queue<int> q;
    dist[s] = 0;
    q.push(s);
    while (!q.empty()) {
      int x = q.front();
      q.pop();
      for (int i : edge[x]) {
        if (i < 0) {
          i = ~i;
          if (dist[es[i].x] != -1) continue;
          if (es[i].rc > 0) {
            dist[es[i].x] = dist[x] + 1;
            q.push(es[i].x);
          }
        } else {
          if (dist[es[i].y] != -1) continue;
          if (es[i].c > 0) {
            dist[es[i].y] = dist[x] + 1;
            q.push(es[i].y);
          }
        }
      }
    }
    return dist[e] != -1;
  }
  T dfs(int x, T f) {
    if (x == e) return f;
    for (int &i = it[x]; i < edge[x].size(); ++i) {
      int y;
      T c;
      if (edge[x][i] < 0)
        y = es[~edge[x][i]].x, c = es[~edge[x][i]].rc;
      else
        y = es[edge[x][i]].y, c = es[edge[x][i]].c;
      if (dist[x] + 1 != dist[y]) continue;
      if (c == 0) continue;
      c = dfs(y, min(f, c));
      if (c > 0) {
        if (edge[x][i] < 0) {
          es[~edge[x][i]].c += c;
          es[~edge[x][i]].rc -= c;
          nowFlow[~edge[x][i]] -= c;
        } else {
          es[edge[x][i]].c -= c;
          es[edge[x][i]].rc += c;
          nowFlow[edge[x][i]] += c;
        }
        return c;
      }
    }
    return 0;
  }
  int matchdfs(int x) {
    if (::n + ::sz <= x && x < ::n + ::sz + ::m) return x - ::n - sz + 1;
    for (int &i = it[x]; i < edge[x].size(); ++i) {
      int y;
      T c;
      if (edge[x][i] < 0)
        y = es[~edge[x][i]].x, c = -nowFlow[~edge[x][i]];
      else
        y = es[edge[x][i]].y, c = nowFlow[edge[x][i]];
      if (c <= 0) continue;
      if (edge[x][i] < 0)
        ++nowFlow[~edge[x][i]];
      else
        --nowFlow[edge[x][i]];
      return matchdfs(y);
    }
    return 0;
  }

 public:
  void init(int N) {
    n = N;
    inf = 0;
    edge.clear();
    edge.resize(n);
    dist.resize(n);
    it.resize(n);
    nowFlow.clear();
    es.clear();
  }
  int addEdge(int x, int y, T C, T RC) {
    inf = max(inf, C + RC);
    int idx = es.size();
    es.emplace_back(x, y, C, RC);
    nowFlow.push_back(0);
    edge[x].push_back(idx);
    edge[y].push_back(~idx);
    return idx;
  }
  T findMaximumFlow(int source, int sink) {
    s = source;
    e = sink;
    T flow = 0;
    while (bfs()) {
      for (int i = 0; i < n; ++i) it[i] = 0;
      while (1) {
        T ret = dfs(s, inf);
        if (ret == 0) break;
        flow += ret;
      }
    }
    return flow;
  }
  T getFlow(int idx) { return nowFlow[idx]; }
  void findMatching() {
    for (int i = 0; i < n; ++i) it[i] = 0;
    for (int i = 1; i <= ::n; ++i) {
      int r = matchdfs(i);
      if (r) {
        gos[i].push_back(r);
        rev[r] = i;
        --i;
      }
    }
  }
};
struct weapon {
  int type;
  int l, r;
  vector<int> ps;
  void scan() {
    cin >> type;
    if (type == 0) {
      int k, x;
      cin >> k;
      for (int i = 0; i < k; ++i) {
        cin >> x;
        ps.push_back(x);
      }
    } else if (type == 1) {
      cin >> l >> r;
    } else {
      for (int i = 0; i < 3; ++i) {
        int x;
        cin >> x;
        ps.push_back(x);
      }
    }
  }
} wps[5001];
Dinic<int> dinic;
int main() {
  ios_base::sync_with_stdio(0);
  cin.tie(0);
  cin >> n >> m;
  for (int i = 1; i <= n; ++i) {
    wps[i].scan();
  }
  dinic.init(n + sz + m + 10);
  int S = 0, E = n + sz + m + 9;
  for (int i = sz + m - 1; i > 1; --i) {
    dinic.addEdge(n + (i >> 1), n + i, m, 0);
  }
  for (int i = 1; i <= n; ++i) {
    dinic.addEdge(S, i, wps[i].type == 2 ? 2 : 1, 0);
    if (wps[i].type == 1) {
      int s = sz + wps[i].l - 1, e = sz + wps[i].r - 1;
      while (s <= e) {
        if ((s & 1) == 1) dinic.addEdge(i, n + (s++), 1, 0);
        if ((e & 1) == 0) dinic.addEdge(i, n + (e--), 1, 0);
        s >>= 1;
        e >>= 1;
      }
    } else {
      for (int j : wps[i].ps) dinic.addEdge(i, n + sz + j - 1, 1, 0);
    }
  }
  for (int i = 0; i < m; ++i) {
    dinic.addEdge(n + sz + i, E, 1, 0);
  }
  int ans = dinic.findMaximumFlow(S, E);
  printf("%d\n", ans);
  dinic.findMatching();
  for (int i = 1; i <= n; ++i) {
    if (wps[i].type != 2) continue;
    if (gos[i].size() != 1) continue;
    for (int j = 0; j < 3; ++j) {
      if (gos[i][0] == wps[i].ps[j]) continue;
      gos[rev[wps[i].ps[j]]].clear();
      rev[wps[i].ps[j]] = i;
      gos[i].push_back(wps[i].ps[j]);
      break;
    }
  }
  for (int i = 1; i <= n; ++i) {
    for (int j : gos[i]) {
      printf("%d %d\n", i, j);
    }
  }
}
