#include <bits/stdc++.h>
using namespace std;
const int maxn = 2e5 + 5;
const long long inf = 1e18;
int n, m, k, x, rt1, rt2, cnt, op, lim, mx, S, T, tot = 1, A, B, id[maxn],
                                                  num[maxn];
int C, _x[maxn], _a[maxn], _b[maxn], _c[maxn];
bool flag[maxn];
int head[maxn], to[maxn], nxt[maxn], cur[maxn];
int depth[maxn];
queue<int> q;
long long w[maxn];
long long maxflow, flow;
void add(int x, int y, long long v) {
  to[++tot] = y, w[tot] = v, nxt[tot] = head[x], head[x] = tot;
  to[++tot] = x, w[tot] = 0, nxt[tot] = head[y], head[y] = tot;
}
int pp;
bool bfs() {
  memset(depth, 0, sizeof depth);
  while (q.size()) q.pop();
  q.push(S);
  depth[S] = 1;
  while (!q.empty()) {
    int x = q.front();
    q.pop();
    for (int i = head[x]; i; i = nxt[i]) {
      if (w[i] && !depth[to[i]]) {
        depth[to[i]] = depth[x] + 1;
        q.push(to[i]);
        if (to[i] == T) return true;
      }
    }
  }
  return false;
}
int dfs(int x, long long flow) {
  if (x == T) return flow;
  for (int &i = cur[x]; i; i = nxt[i]) {
    if (w[i] && depth[to[i]] == depth[x] + 1) {
      long long U = dfs(to[i], min(flow, w[i]));
      w[i] -= U;
      w[i ^ 1] += U;
      if (U) return U;
    }
  }
  return 0;
}
void dinic() {
  while (bfs()) {
    for (int i = 1; i <= mx + n + 2; i++) cur[i] = head[i];
    while (flow = dfs(S, inf)) maxflow += flow;
  }
}
void build(int x, int l, int r) {
  mx = max(mx, x);
  if (l == r) {
    id[l] = x;
    num[x] = l;
    return;
  }
  int mid = (l + r) >> 1;
  build((x << 1), l, mid), build((x << 1 | 1), mid + 1, r);
  add(x, (x << 1), inf), add(x, (x << 1 | 1), inf);
}
void modify(int x, int nl, int nr, int l, int r, int v) {
  if (nl <= l && r <= nr) {
    add(v, x, 1);
    return;
  }
  int mid = (l + r) >> 1;
  if (nl <= mid) modify((x << 1), nl, nr, l, mid, v);
  if (nr > mid) modify((x << 1 | 1), nl, nr, mid + 1, r, v);
}
int find(int x, int fa) {
  if (mx + 1 <= x && x <= mx + n) return x - mx;
  for (int i = head[x]; i; i = nxt[i])
    if (w[i] && to[i] != fa) {
      --w[i];
      ++w[i ^ 1];
      return find(to[i], x);
    }
  return 0;
}
int main() {
  scanf("%d%d", &n, &m);
  build(1, 1, m);
  S = mx + n + 1, T = S + 1;
  for (int i = 1; i <= n; i++) {
    scanf("%d", &op);
    if (op == 0) {
      add(S, mx + i, 1);
      scanf("%d", &k);
      while (k--) scanf("%d", &x), add(mx + i, id[x], 1);
    } else if (op == 1) {
      add(S, mx + i, 1);
      scanf("%d%d", &A, &B);
      modify(1, A, B, 1, m, mx + i);
    } else if (op == 2) {
      _x[++C] = i;
      scanf("%d%d%d", &_a[C], &_b[C], &_c[C]);
    }
  }
  for (int i = 1; i <= C; i++) {
    add(S, mx + _x[i], 2);
    add(mx + _x[i], id[_a[i]], 1);
    add(mx + _x[i], id[_b[i]], 1);
    add(mx + _x[i], id[_c[i]], 1);
  }
  for (int i = 1; i <= m; i++) add(id[i], T, 1);
  dinic();
  printf("%lld\n", maxflow);
  for (int i = head[T]; i; i = nxt[i]) {
    if (!w[i]) continue;
    int nw = find(to[i], T);
    if (nw) printf("%d %d\n", nw, num[to[i]]);
  }
  return 0;
}
