#include <bits/stdc++.h>
using namespace std;
const int mod = 1e9 + 7;
const int maxm = 1e5 + 10;
const int maxn = 2e7 + 10;
const int inf = 0x3f3f3f3f;
namespace io {
const int SIZE = (1 << 21) + 1;
char ibuf[SIZE], *iS, *iT, obuf[SIZE], *oS = obuf, *oT = oS + SIZE - 1, c,
                                       qu[55];
int f, qr;
inline void flush() {
  fwrite(obuf, 1, oS - obuf, stdout);
  oS = obuf;
}
inline void putc(char x) {
  *oS++ = x;
  if (oS == oT) flush();
}
template <typename A>
inline bool read(A &x) {
  for (f = 1, c = (iS == iT ? (iT = (iS = ibuf) + fread(ibuf, 1, SIZE, stdin),
                              (iS == iT ? EOF : *iS++))
                            : *iS++);
       c < '0' || c > '9';
       c = (iS == iT ? (iT = (iS = ibuf) + fread(ibuf, 1, SIZE, stdin),
                       (iS == iT ? EOF : *iS++))
                     : *iS++))
    if (c == '-')
      f = -1;
    else if (c == EOF)
      return 0;
  for (x = 0; c <= '9' && c >= '0';
       c = (iS == iT ? (iT = (iS = ibuf) + fread(ibuf, 1, SIZE, stdin),
                       (iS == iT ? EOF : *iS++))
                     : *iS++))
    x = x * 10 + (c & 15);
  x *= f;
  return 1;
}
inline bool read(char &x) {
  while ((x = (iS == iT ? (iT = (iS = ibuf) + fread(ibuf, 1, SIZE, stdin),
                           (iS == iT ? EOF : *iS++))
                        : *iS++)) == ' ' ||
         x == '\n' || x == '\r')
    ;
  return x != EOF;
}
inline bool read(char *x) {
  while ((*x = (iS == iT ? (iT = (iS = ibuf) + fread(ibuf, 1, SIZE, stdin),
                            (iS == iT ? EOF : *iS++))
                         : *iS++)) == '\n' ||
         *x == ' ' || *x == '\r')
    ;
  if (*x == EOF) return 0;
  while (!(*x == '\n' || *x == ' ' || *x == '\r' || *x == EOF))
    *(++x) = (iS == iT ? (iT = (iS = ibuf) + fread(ibuf, 1, SIZE, stdin),
                          (iS == iT ? EOF : *iS++))
                       : *iS++);
  *x = 0;
  return 1;
}
template <typename A, typename... B>
inline bool read(A &x, B &...y) {
  return read(x) && read(y...);
}
template <typename A>
inline bool write(A x) {
  if (!x) putc('0');
  if (x < 0) putc('-'), x = -x;
  while (x) qu[++qr] = x % 10 + '0', x /= 10;
  while (qr) putc(qu[qr--]);
  return 0;
}
inline bool write(char x) {
  putc(x);
  return 0;
}
inline bool write(const char *x) {
  while (*x) {
    putc(*x);
    ++x;
  }
  return 0;
}
inline bool write(char *x) {
  while (*x) {
    putc(*x);
    ++x;
  }
  return 0;
}
template <typename A, typename... B>
inline bool write(A x, B... y) {
  return write(x) || write(y...);
}
struct Flusher_ {
  ~Flusher_() { flush(); }
} io_flusher_;
}  // namespace io
using io ::putc;
using io ::read;
using io ::write;
int s, t;
int now[maxm], dep[maxm], head[maxm], omg[maxm], ok[maxm], num[maxm],
    used[maxm];
struct edge {
  int v, w, nxt;
} e[maxm * 8];
struct node {
  int ls, rs;
} tree[maxm];
struct OMG {
  int l, r, id;
  friend bool operator<(OMG a, OMG b) { return a.r > b.r; }
} a[maxm];
bool cmp(OMG a, OMG b) { return a.l < b.l; }
priority_queue<OMG> pq;
int weapon[maxm];
int ecnt, cnt;
void addedge(int u, int v, int w) {
  e[ecnt] = {v, w, head[u]};
  head[u] = ecnt++;
  e[ecnt] = {u, 0, head[v]};
  head[v] = ecnt++;
}
int bfs() {
  queue<int> q;
  while (!q.empty()) q.pop();
  for (int i = s; i <= t; i++) {
    dep[i] = -1;
    now[i] = -1;
  }
  dep[s] = 0;
  q.push(s);
  now[s] = head[s];
  while (!q.empty()) {
    int u = q.front();
    q.pop();
    for (int i = head[u]; i != -1; i = e[i].nxt) {
      int v = e[i].v;
      if (e[i].w > 0 && dep[v] == -1) {
        dep[v] = dep[u] + 1;
        now[v] = head[v];
        q.push(v);
      }
    }
  }
  return dep[t] != -1;
}
int dfs(int u, int mi) {
  if (mi == 0 || u == t) return mi;
  int tmp, sum = 0;
  for (int i = now[u]; i != -1 && mi; i = e[i].nxt) {
    now[u] = i;
    int v = e[i].v;
    if (e[i].w > 0 && dep[v] == dep[u] + 1) {
      tmp = dfs(v, min(mi, e[i].w));
      e[i].w -= tmp;
      e[i ^ 1].w += tmp;
      sum += tmp;
      mi -= tmp;
      if (!mi) break;
    }
  }
  return sum;
}
int dinic() {
  int ans = 0;
  while (bfs()) {
    ans += dfs(s, inf);
  }
  return ans;
}
void buildin(int l, int r, int &rt) {
  if (l == r) {
    rt = l;
    return;
  }
  int mid = l + r >> 1;
  if (!rt) rt = ++cnt;
  buildin(l, mid, tree[rt].ls);
  buildin(mid + 1, r, tree[rt].rs);
  addedge(tree[rt].ls, rt, inf);
  addedge(tree[rt].rs, rt, inf);
}
void update(int L, int R, int l, int r, int rt, int u) {
  if (L <= l && r <= R) {
    addedge(rt, u, 1);
    return;
  }
  int mid = l + r >> 1;
  if (L <= mid) update(L, R, l, mid, tree[rt].ls, u);
  if (R > mid) update(L, R, mid + 1, r, tree[rt].rs, u);
}
int main() {
  memset(head, -1, sizeof(head));
  int n, m;
  read(n, m);
  s = 0, t = n + m + 1;
  cnt = n + m;
  int rt = 0;
  buildin(1, m, rt);
  int zz = cnt, hh = 0;
  for (int i = 1; i <= n; i++) {
    int op;
    read(op);
    if (op == 0) {
      int k;
      read(k);
      for (int j = 1; j <= k; j++) {
        int id;
        read(id);
        addedge(id, m + i, 1);
      }
    }
    if (op == 1) {
      int l, r;
      read(l, r);
      update(l, r, 1, m, rt, m + i);
      a[++hh] = {l, r, i};
    }
    if (op == 2) {
      int a, b, c;
      read(a, b, c);
      zz++;
      addedge(s, zz, 1);
      addedge(zz, a, 1);
      addedge(zz, b, 1);
      addedge(zz, c, 1);
      omg[a] = omg[b] = omg[c] = i;
      num[i] = 2;
    }
    weapon[i] = op;
  }
  t = zz + 1;
  for (int i = 1; i <= n; i++) addedge(m + i, t, 1);
  for (int i = 1; i <= m; i++)
    if (!omg[i]) addedge(s, i, 1);
  int ans = dinic();
  printf("%d\n", ans + 2 * (zz - cnt));
  sort(a + 1, a + hh + 1, cmp);
  for (int i = 1; i <= m; i++) {
    int flag = 0;
    for (int j = head[i]; j != -1; j = e[j].nxt) {
      if (j % 2 == 0) continue;
      if (e[j].w == 1) {
        flag = 1;
        break;
      }
    }
    if (!flag) continue;
    int now = i;
    for (int j = head[now]; j != -1; j = e[j].nxt) {
      if (j % 2 == 1) continue;
      if ((e[j].v > m && e[j].v <= m + n) && (e[j].w == 0) &&
          weapon[e[j].v - m] == 0) {
        now = e[j].v;
        break;
      }
    }
    if (now > m && now <= m + n && weapon[now - m] == 0) {
      printf("%d %d\n", now - m, i);
      ok[i] = 1;
    }
  }
  int pt = 0;
  for (int i = 1; i <= m; i++) {
    int flag = 0;
    for (int j = head[i]; j != -1; j = e[j].nxt) {
      if (j % 2 == 0) continue;
      if (e[j].w == 1) {
        flag = 1;
        break;
      }
    }
    if (!flag) continue;
    if (ok[i]) continue;
    while (pt < hh && a[pt + 1].l <= i) {
      pq.push(a[pt + 1]);
      pt++;
    }
    while (!pq.empty()) {
      if (pq.top().r < i) {
        pq.pop();
      } else
        break;
    }
    if (!pq.empty()) {
      printf("%d %d\n", pq.top().id, i);
      pq.pop();
      ok[i] = 1;
    }
  }
  for (int i = 1; i <= m; i++) {
    if (omg[i] && (ok[i] == 0) && num[omg[i]] > 0) {
      printf("%d %d\n", omg[i], i);
      num[omg[i]]--;
    }
  }
  return 0;
}
