#include <bits/stdc++.h>
using namespace std;
const int N = 1e6;
const int inf = 1e9;
vector<int> Eid[N];
int n, m, cnt, S, T, in[N], out[N], cur[N], d[N];
struct Edge {
  int c, v;
} E[N];
void AddEdge(int x, int y, int c) {
  E[cnt].v = y, E[cnt].c = c;
  Eid[x].push_back(cnt++);
  E[cnt].v = x, E[cnt].c = 0;
  Eid[y].push_back(cnt++);
}
bool BFS() {
  static int Q[N];
  int x, ql, qr;
  for (int i = 0; i <= T; i++) d[i] = -1;
  Q[ql = qr = 0] = S;
  d[S] = 0;
  while (ql <= qr) {
    x = Q[ql++];
    for (int i = 0; i < Eid[x].size(); i++) {
      const Edge &e = E[Eid[x][i]];
      if (e.c && d[e.v] == -1) {
        Q[++qr] = e.v;
        d[e.v] = d[x] + 1;
        if (e.v == T) return 1;
      }
    }
  }
  return 0;
}
int Aug(int x, int a) {
  if (x == T) return a;
  int aug = 0, delta;
  for (int &i = cur[x]; i < Eid[x].size(); i++) {
    Edge &e = E[Eid[x][i]];
    if (e.c && d[e.v] == d[x] + 1) {
      delta = Aug(e.v, min(a, e.c));
      if (delta) {
        e.c -= delta;
        E[Eid[x][i] ^ 1].c += delta;
        aug += delta;
        if (!(a -= delta)) break;
      }
    }
  }
  if (!aug) d[x] = -1;
  return aug;
}
int MaxFlow() {
  int flow = 0;
  while (BFS()) {
    for (int i = 0; i <= T; i++) cur[i] = 0;
    flow += Aug(S, inf);
  }
  return flow;
}
int type[N], id[N], a[N], b[N], c[N], belong[N];
void build(int k, int l, int r) {
  if (l == r) {
    id[l] = k;
    return;
  }
  AddEdge(k, k << 1, inf);
  AddEdge(k, k << 1 | 1, inf);
  int mid = l + r >> 1;
  build(k << 1, l, mid);
  build(k << 1 | 1, mid + 1, r);
}
void work(int k, int l, int r, int p, int q, int id) {
  if (l >= p && r <= q) {
    AddEdge(id, k, 1);
    return;
  }
  if (l > q || r < p) return;
  int mid = l + r >> 1;
  work(k << 1, l, mid, p, q, id);
  work(k << 1 | 1, mid + 1, r, p, q, id);
}
int cnt2 = 0, edgeid[N];
int main() {
  cin >> n >> m;
  S = 0;
  T = m * 4 + n + n + 1;
  build(1, 1, m);
  for (int i = 1; i <= n; ++i) {
    scanf("%d", type + i);
    if (type[i] == 0) {
      int x, k;
      AddEdge(S, m * 4 + i, 1);
      scanf("%d", &k);
      while (k--) {
        scanf("%d", &x);
        AddEdge(m * 4 + i, id[x], 1);
      }
    } else if (type[i] == 1) {
      int l, r;
      scanf("%d %d", &l, &r);
      AddEdge(S, m * 4 + i, 1);
      work(1, 1, m, l, r, m * 4 + i);
    } else {
      cnt2++;
      scanf("%d %d %d", a + i, b + i, c + i);
      belong[a[i]] = belong[b[i]] = belong[c[i]] = i;
      AddEdge(4 * m + i + n, T, 1);
    }
  }
  for (int i = 1; i <= m; ++i) {
    edgeid[i] = cnt;
    if (!belong[i]) {
      AddEdge(id[i], T, 1);
    } else {
      AddEdge(id[i], 4 * m + n + belong[i], 1);
    }
  }
  cout << MaxFlow() + 2 * cnt2 << endl;
  for (int i = 1; i <= n; ++i) {
    if (type[i] == 2) {
      if (E[edgeid[a[i]]].c == 0) {
        printf("%d %d\n%d %d\n", i, b[i], i, c[i]);
      } else if (E[edgeid[b[i]]].c == 0) {
        printf("%d %d\n%d %d\n", i, a[i], i, c[i]);
      } else {
        printf("%d %d\n%d %d\n", i, b[i], i, a[i]);
      }
    }
  }
  for (int i = 1; i <= m; ++i) {
    if (E[edgeid[i]].c == 0) {
      int x = id[i], y;
      while (x) {
        for (int i = 0; i < Eid[x].size(); ++i) {
          int e = Eid[x][i];
          if (e % 2 == 0) continue;
          if (E[e].c == 0) continue;
          E[e].c--;
          E[e ^ 1].c++;
          y = x;
          x = E[e].v;
          break;
        }
      }
      printf("%d %d\n", y - 4 * m, i);
    }
  }
}
