#include <bits/stdc++.h>
using namespace std;
struct Edge {
  int to, flow;
};
template <int MAXN>
struct Dinic {
  int s, t, P[MAXN], D[MAXN], qu[MAXN];
  vector<int> Adj[MAXN];
  vector<Edge> E;
  inline void Add(int v, int u, int w) {
    Adj[v].push_back(E.size());
    E.push_back({u, w});
    Adj[u].push_back(E.size());
    E.push_back({v, 0});
  }
  inline bool BFS() {
    int l = 0, r = 0;
    memset(P, 0, sizeof(P));
    memset(D, -1, sizeof(D));
    qu[r++] = s;
    D[s] = 0;
    while (r - l) {
      int v = qu[l++];
      for (int &id : Adj[v])
        if (E[id].flow && D[E[id].to] == -1) {
          D[E[id].to] = D[v] + 1;
          if (E[id].to == t) return (1);
          qu[r++] = E[id].to;
        }
    }
    return (0);
  }
  int DFS(int v, int flow) {
    if (v == t) return (flow);
    int Flow = 0;
    for (int i = P[v]; i < (int)Adj[v].size(); i++) {
      int id = Adj[v][i];
      if (E[id].flow && D[E[id].to] == D[v] + 1) {
        int _flow = DFS(E[id].to, min(flow, E[id].flow));
        if (!_flow) swap(Adj[v][i], Adj[v][P[v]]), P[v]++;
        E[id].flow -= _flow;
        E[id ^ 1].flow += _flow;
        Flow += _flow;
        flow -= _flow;
        if (!flow) return Flow;
      } else
        swap(Adj[v][i], Adj[v][P[v]]), P[v]++;
    }
    return Flow;
  }
  inline int MaxFlow(int _s, int _t) {
    int Flow = 0;
    s = _s;
    t = _t;
    while (BFS()) Flow += DFS(s, INT_MAX);
    return Flow;
  }
};
const int N = 5005;
int n, m, A[N], B[N], C[N], D[N];
Dinic<N * 6> G;
void Build(int id = 1, int l = 1, int r = m + 1) {
  if (r - l < 2) {
    G.Add(n + m + 1 + id, n + 1 + l, 1);
    return;
  }
  Build(id << 1, l, l + r >> 1);
  Build(id << 1 ^ 1, l + r >> 1, r);
  G.Add(n + m + 1 + id, n + m + 1 + (id << 1), INT_MAX);
  G.Add(n + m + 1 + id, n + m + 1 + (id << 1 ^ 1), INT_MAX);
}
void Add(int le, int ri, int v, int id = 1, int l = 1, int r = m + 1) {
  if (ri <= l || r <= le) return;
  if (le <= l && r <= ri) {
    G.Add(v, n + m + 1 + id, 1);
    return;
  }
  Add(le, ri, v, id << 1, l, l + r >> 1);
  Add(le, ri, v, id << 1 ^ 1, l + r >> 1, r);
}
void DFS(vector<int> vec, int id = 1, int l = 1, int r = m + 1) {
  for (int &e : G.Adj[n + m + 1 + id])
    if (G.E[e].to <= n + 1 && G.E[e].flow) vec.push_back(G.E[e].to - 1);
  if (r - l < 2) {
    assert((int)vec.size() <= 1);
    if (vec.size()) D[l] = vec[0];
    return;
  }
  int el = -1, er = -1;
  for (int &e : G.Adj[n + m + 1 + id])
    if (G.E[e].to > n + m + 1 + id) {
      if (el == -1)
        el = e;
      else
        er = e;
    }
  assert(el != -1);
  assert(er != -1);
  if (G.E[el].to > G.E[er].to) swap(el, er);
  vector<int> L;
  assert(G.E[el ^ 1].flow <= (int)vec.size());
  for (int i = 0; i < G.E[el ^ 1].flow; i++)
    L.push_back(vec.back()), vec.pop_back();
  DFS(L, id << 1, l, l + r >> 1);
  DFS(vec, id << 1 ^ 1, l + r >> 1, r);
}
int main() {
  scanf("%d%d", &n, &m);
  Build();
  for (int i = 1; i <= n; i++) {
    int tp;
    scanf("%d", &tp);
    if (tp == 0) {
      int k, v;
      scanf("%d", &k);
      for (; k; k--) scanf("%d", &v), G.Add(i + 1, n + 1 + v, 1);
      G.Add(0, i + 1, 1);
    } else if (tp == 1) {
      int l, r;
      scanf("%d%d", &l, &r);
      Add(l, r + 1, i + 1);
      G.Add(0, i + 1, 1);
    } else {
      int a, b, c;
      scanf("%d%d%d", &a, &b, &c);
      A[i] = a;
      B[i] = b;
      C[i] = c;
      G.Add(i + 1, n + 1 + a, 1);
      G.Add(i + 1, n + 1 + b, 1);
      G.Add(i + 1, n + 1 + c, 1);
      G.Add(0, i + 1, 2);
    }
  }
  for (int i = 1; i <= m; i++) G.Add(n + 1 + i, 1, 1);
  printf("%d\n", G.MaxFlow(0, 1));
  for (int i = 1; i <= n; i++)
    for (int &id : G.Adj[i + 1])
      if (G.E[id].to != 0 && G.E[id].to <= n + 1 + m && G.E[id ^ 1].flow)
        D[G.E[id].to - n - 1] = i;
  vector<int> vec;
  DFS(vec);
  for (int i = 1; i <= n; i++)
    if (A[i]) {
      for (int &id : G.Adj[i + 1])
        if (G.E[id].to == 0) {
          if (G.E[id].flow == 2)
            break;
          else if (G.E[id].flow == 1) {
            if (D[A[i]] != i)
              D[A[i]] = i;
            else
              D[B[i]] = i;
          } else
            D[A[i]] = D[B[i]] = i;
        }
    }
  for (int i = 1; i <= m; i++)
    if (D[i]) printf("%d %d\n", D[i], i);
  return 0;
}
