#include <bits/stdc++.h>
using namespace std;
inline int read(void) {
  int x = 0, f = 1;
  char ch = getchar();
  while (ch < '0' || ch > '9') {
    if (ch == '-') f = -1;
    ch = getchar();
  }
  while (ch >= '0' && ch <= '9') {
    x = x * 10 + ch - '0';
    ch = getchar();
  }
  return f * x;
}
const int maxn = 5005, inf = 0x3f3f3f3f, maxv = maxn + maxn * 4, maxk = 1e5 + 5;
const int maxe = maxn + maxk + maxn * 14 + 4 * maxn * 2 + maxn;
int n, m, head[maxv], tot = 1, S, T;
int cur[maxv], d[maxv], id[maxn << 2], ans[maxn];
bool is_second[maxn];
int spe[maxn][3], cnt[maxn];
struct Edge {
  int y, next, w;
  Edge() {}
  Edge(int _y, int _next, int _w) : y(_y), next(_next), w(_w) {}
} e[maxe << 1];
inline void connect(int x, int y, int w) {
  e[++tot] = Edge(y, head[x], w);
  head[x] = tot;
}
inline int get(int x) { return x + 4 * m; }
struct SegmentTree {
  int L[maxn << 2], R[maxn << 2];
  void build(int o, int l, int r) {
    L[o] = l;
    R[o] = r;
    if (l == r) {
      connect(o, T, 1);
      connect(T, o, 0);
      id[o] = l;
      return;
    }
    int mid = (l + r) >> 1;
    build((o << 1), l, mid);
    build((o << 1 | 1), mid + 1, r);
    connect(o, (o << 1), inf);
    connect((o << 1), o, 0);
    connect(o, (o << 1 | 1), inf);
    connect((o << 1 | 1), o, 0);
  }
  void add(int o, int ql, int qr, int fr) {
    if (ql <= L[o] && R[o] <= qr) {
      connect(fr, o, 1);
      connect(o, fr, 0);
      return;
    }
    int mid = (L[o] + R[o]) >> 1;
    if (ql <= mid) add((o << 1), ql, qr, fr);
    if (qr > mid) add((o << 1 | 1), ql, qr, fr);
  }
  int find(int o, int q) {
    if (L[o] == R[o]) {
      return o;
    }
    int mid = (L[o] + R[o]) >> 1;
    if (q <= mid)
      return find((o << 1), q);
    else
      return find((o << 1 | 1), q);
  }
} Tree;
inline bool bfs(void) {
  queue<int> q;
  q.push(S);
  memset(d, -1, sizeof d);
  d[S] = 1;
  cur[S] = head[S];
  while (q.size()) {
    int x = q.front();
    q.pop();
    for (int i = head[x]; i; i = e[i].next) {
      int y = e[i].y;
      if (d[y] == -1 && e[i].w) {
        d[y] = d[x] + 1;
        cur[y] = head[y];
        if (y == T) return true;
        q.push(y);
      }
    }
  }
  return false;
}
int find(int x, int limit) {
  if (x == T) return limit;
  int flow = 0;
  for (int i = cur[x]; i && flow < limit; i = e[i].next) {
    int y = e[i].y;
    cur[x] = i;
    if (d[y] == d[x] + 1 && e[i].w) {
      int t = find(y, min(e[i].w, limit - flow));
      if (!t) d[y] = -1;
      e[i].w -= t;
      e[i ^ 1].w += t;
      flow += t;
    }
  }
  return flow;
}
inline int dinic(void) {
  int r = 0, flow;
  while (bfs())
    while ((flow = find(S, inf)) > 0) r += flow;
  return r;
}
void scheme(int now, int& s) {
  if (s) return;
  if (4 * m + 1 <= now && now <= 4 * m + n) {
    s = now - 4 * m;
    return;
  }
  for (int i = head[now]; i; i = e[i].next) {
    int y = e[i].y;
    if ((i & 1) && e[i].w) {
      scheme(y, s);
      --e[i].w;
      return;
    }
  }
}
int main() {
  n = read();
  m = read();
  S = 0;
  T = n + 4 * m + 1;
  Tree.build(1, 1, m);
  for (int i = 1; i <= n; ++i) {
    int opt = read();
    if (opt == 0) {
      int K = read();
      while (K--) {
        int x = read();
        connect(get(i), Tree.find(1, x), 1);
        connect(Tree.find(1, x), get(i), 0);
      }
      connect(S, get(i), 1);
      connect(get(i), S, 0);
    } else if (opt == 1) {
      int l = read(), r = read();
      Tree.add(1, l, r, get(i));
      connect(S, get(i), 1);
      connect(get(i), S, 0);
    } else if (opt == 2) {
      int a = read(), b = read(), c = read();
      connect(get(i), Tree.find(1, a), 1);
      connect(Tree.find(1, a), get(i), 0);
      connect(get(i), Tree.find(1, b), 1);
      connect(Tree.find(1, b), get(i), 0);
      connect(get(i), Tree.find(1, c), 1);
      connect(Tree.find(1, c), get(i), 0);
      connect(S, get(i), 2);
      connect(get(i), S, 0);
      is_second[i] = true;
      spe[i][0] = a;
      spe[i][1] = b;
      spe[i][2] = c;
    }
  }
  int tmp = dinic();
  printf("%d\n", tmp);
  for (int i = head[T]; i; i = e[i].next) {
    int y = e[i].y;
    if (e[i].w) {
      scheme(y, ans[id[y]]);
    }
  }
  for (int i = 1; i <= m; ++i) {
    ++cnt[ans[i]];
  }
  for (int i = 1; i <= n; ++i) {
    if (cnt[i] == 1 && is_second[i]) {
      if (ans[spe[i][0]] != i)
        ans[spe[i][0]] = i;
      else
        ans[spe[i][1]] = i;
    }
  }
  for (int i = 1; i <= m; ++i) {
    if (ans[i]) printf("%d %d\n", ans[i], i);
  }
  return 0;
}
