#include <bits/stdc++.h>
using namespace std;
int n, m, ecnt, p[5050][3], vis[5050], ans, cont[5050], s, t, ok[5050],
    q[5050 << 5], level[5050 << 4];
struct node {
  int v, c, k;
  node *next, *rev;
} pool[3000000], *h[5050 << 4], *cur[5050 << 4];
inline void adde(int u, int v, int c) {
  node *p = &pool[ecnt++], *q = &pool[ecnt++];
  *p = node{v, c, 1, h[u], q}, h[u] = p;
  *q = node{u, 0, 0, h[v], p}, h[v] = q;
}
void build(int u, int l, int r) {
  t = max(u + n + m + 1, t);
  if (l == r) return adde(u + n + m, l + m, (1 << 20));
  int mid = (l + r) >> 1;
  build(u << 1, l, mid), build(u << 1 | 1, mid + 1, r);
  adde(u + n + m, (u << 1) + n + m, (1 << 20)),
      adde(u + n + m, (u << 1 | 1) + n + m, (1 << 20));
}
void change(int u, int l, int r, int tl, int tr, int x) {
  if (tl <= l && r <= tr) return adde(x, u + n + m, (1 << 20));
  int mid = (l + r) >> 1;
  if (tl <= mid) change(u << 1, l, mid, tl, tr, x);
  if (mid < tr) change(u << 1 | 1, mid + 1, r, tl, tr, x);
}
bool bfs() {
  int front = 0, rear = 1;
  memset(level, 0, sizeof(level)), level[s] = 1, q[0] = s;
  while (front < rear) {
    int u = q[front++];
    for (node *p = h[u]; p; p = p->next) {
      if (p->c && !level[p->v]) {
        level[p->v] = level[u] + 1;
        q[rear++] = p->v;
        if (p->v == t) return 1;
      }
    }
  }
  return 0;
}
int dfs(int u, int f) {
  if (u == t) return f;
  int F, flow = 0;
  for (node *&p = cur[u]; p; p = p->next) {
    if (p->c && level[p->v] == level[u] + 1) {
      F = dfs(p->v, min(f - flow, p->c));
      flow += F, p->c -= F, p->rev->c += F;
      if (flow == f) return flow;
    }
  }
  return flow;
}
int Dinic() {
  int ret = 0;
  while (bfs()) {
    for (register int i = s; i <= t; ++i) cur[i] = h[i];
    ret += dfs(s, (1 << 20));
  }
  return ret;
}
int search(int u) {
  if (m + 1 <= u && u <= m + n) return u;
  for (node *p = h[u]; p; p = p->next) {
    if (p->k && p->c != (1 << 20)) {
      ++p->c;
      return search(p->v);
    }
  }
}
int main() {
  int op, l, r, k;
  scanf("%d%d", &m, &n);
  build(1, 1, n);
  for (register int i = 1; i <= m; ++i) {
    scanf("%d", &op);
    if (op == 0) {
      adde(s, i, 1);
      scanf("%d", &k);
      while (k--) scanf("%d", &l), change(1, 1, n, l, l, i);
    } else if (op == 1) {
      adde(s, i, 1);
      scanf("%d%d", &l, &r);
      change(1, 1, n, l, r, i);
    } else {
      adde(i, t, 1);
      scanf("%d%d%d", &l, &r, &k);
      cont[l] = cont[r] = cont[k] = i, ans += 2;
      p[i][0] = l, p[i][1] = r, p[i][2] = k;
    }
  }
  for (register int i = 1; i <= n; ++i)
    if (!cont[i])
      adde(i + m, t, 1);
    else
      adde(i + m, cont[i], 1);
  ans += Dinic();
  for (node *q = h[s]; q; q = q->next)
    if (!q->c) ok[q->v] = 1;
  printf("%d\n", ans);
  for (register int i = 1; i <= m; ++i) {
    if (!p[i][0] && ok[i]) {
      int target = search(i);
      printf("%d %d\n", i, target - m);
      vis[target - m] = 1;
    }
  }
  for (register int i = 1; i <= m; ++i) {
    if (p[i][0]) {
      if (!vis[p[i][0]]) printf("%d %d\n", i, p[i][0]);
      if (!vis[p[i][1]]) printf("%d %d\n", i, p[i][1]);
      if (vis[p[i][0]] || vis[p[i][1]]) printf("%d %d\n", i, p[i][2]);
    }
  }
  return 0;
}
