#include <bits/stdc++.h>
#pragma GCC optimize(2)
using namespace std;
bool vis[200005];
int n, m, id[200005], q[200005], hd, tl, tot, Begin, ans, d[200005],
    first[200005], cnt, s, t;
struct edge {
  int v, c, next;
};
map<int, int> mp[200005];
edge e[200005];
inline void add(int u, int v, int c) {
  e[++cnt].v = v, e[cnt].c = c, e[cnt].next = first[u], first[u] = cnt;
  e[++cnt].v = u, e[cnt].c = 0, e[cnt].next = first[v], first[v] = cnt;
}
inline bool bfs() {
  queue<int> q;
  q.push(s);
  memset(d, -1, sizeof(d));
  d[s] = 0;
  while (!q.empty()) {
    int x = q.front();
    q.pop();
    for (int i = first[x]; i != -1; i = e[i].next) {
      int v = e[i].v;
      if (e[i].c <= 0 || d[v] != -1) continue;
      d[v] = d[x] + 1;
      if (v == t) return 1;
      q.push(v);
    }
  }
  return 0;
}
inline int dfs(int x, int f) {
  if (!f || x == t) return f;
  int flow = f;
  for (int i = first[x]; i != -1; i = e[i].next) {
    int v = e[i].v;
    if (flow && e[i].c > 0 && d[v] == d[x] + 1) {
      int tmp = dfs(v, min(flow, e[i].c));
      if (tmp == 0) d[v] = -1;
      flow -= tmp;
      e[i].c -= tmp;
      e[i ^ 1].c += tmp;
    }
  }
  return f - flow;
}
inline void solve() {
  while (bfs()) ans += dfs(s, 0x3f3f3f3f);
}
inline void build(int p, int l, int r) {
  id[p] = ++tot;
  if (l == r) return (void)add(id[p], l, 1);
  int mid = (l + r) >> 1;
  build(p << 1, l, mid), build(p << 1 | 1, mid + 1, r);
  add(id[p], id[p << 1], 0x3f3f3f3f), add(id[p], id[p << 1 | 1], 0x3f3f3f3f);
}
inline void update(int p, int l, int r, int ql, int qr) {
  if (ql <= l && qr >= r) return (void)add(tot, id[p], 1);
  int mid = (l + r) >> 1;
  if (ql <= mid) update(p << 1, l, mid, ql, qr);
  if (qr > mid) update(p << 1 | 1, mid + 1, r, ql, qr);
}
int tmp = 0;
inline void query(int p) {
  if (p >= Begin) {
    tmp = p - Begin + 1;
    return;
  }
  map<int, int>::iterator it = mp[p].begin();
  query(it->first);
  --it->second;
  if (!it->second) mp[p].erase(it);
}
int main() {
  memset(first, -1, sizeof(first));
  scanf("%d%d", &n, &m), tot = m, cnt = -1, s = ++tot;
  build(1, 1, m), Begin = tot + 1;
  for (int i = 1; i <= n; ++i) {
    int op;
    scanf("%d", &op);
    ++tot;
    if (op == 0) {
      int k;
      scanf("%d", &k);
      while (k--) {
        int x;
        scanf("%d", &x);
        add(tot, x, 1);
      }
      add(s, tot, 1);
    } else if (op == 1) {
      int ql, qr;
      scanf("%d%d", &ql, &qr);
      update(1, 1, m, ql, qr), add(s, tot, 1);
    } else {
      int a, b, c;
      scanf("%d%d%d", &a, &b, &c);
      vis[a] = vis[b] = 1, ans += 2;
      add(tot, a, 0), e[cnt].c = 1, add(tot, b, 0), e[cnt].c = 1,
                      add(tot, c, 1);
    }
  }
  t = ++tot;
  for (int i = 1; i <= m; ++i)
    if (!vis[i]) add(i, t, 1);
  solve();
  printf("%d\n", ans);
  for (int i = 1; i <= tot; ++i)
    for (int j = first[i]; j; j = e[j].next)
      if ((j & 1) && e[j].c) mp[i][e[j].v] = e[j].c;
  for (int i = 1; i <= m; ++i) {
    bool f = 1;
    for (int j = first[i]; j && f; j = e[j].next)
      if (e[j].v == t && e[j].c) f = 0;
    if (f) query(i), printf("%d %d\n", tmp, i);
  }
  return 0;
}
