#include <bits/stdc++.h>
using namespace std;
const int Nmax = 30025, Mmax = 310005;
int S, D, weapon[Nmax], K, N, M, Nodes, i;
class Floow {
  vector<int> v[Nmax];
  int go[Mmax], c[Mmax], e = 0, dist[Nmax];
  int taken[Nmax], used[Nmax];
  bool bfs() {
    memset(dist, -1, sizeof(dist));
    queue<int> q;
    dist[S] = 0;
    q.push(S);
    int node, it;
    while (q.size()) {
      node = q.front();
      q.pop();
      for (auto e : v[node]) {
        it = go[e];
        if (c[e] && dist[it] == -1) {
          dist[it] = dist[node] + 1;
          q.push(it);
        }
      }
    }
    return dist[D] != -1;
  }
  int dfs(int node, int flow) {
    if (node == D) return flow;
    if (!flow) return 0;
    int add = 0;
    for (auto it : v[node])
      if (dist[go[it]] == dist[node] + 1 && c[it]) {
        int t = dfs(go[it], min(flow, c[it]));
        c[it] -= t;
        c[it ^ 1] += t;
        flow -= t;
        add += t;
      }
    if (!add) dist[node] = -5;
    return add;
  }

 public:
  void add_edge(int x, int y, int cap) {
    v[x].push_back(e);
    v[y].push_back(e ^ 1);
    go[e ^ 1] = x;
    go[e] = y;
    c[e] = cap;
    c[e ^ 1] = 0;
    e += 2;
  }
  int max_flow() {
    int ans = 0;
    while (bfs()) ans += dfs(S, M);
    return ans;
  }
  void reconstruct() {
    int node, e;
    for (auto it : v[D])
      if (!c[it ^ 1]) {
        for (auto e : v[go[it]])
          if ((e & 1) && !c[e ^ 1]) taken[go[it]] = go[e];
      }
    for (node = N + 1; node <= N + M; ++node) ++used[taken[node]];
    for (node = 1; node <= N; ++node)
      if (weapon[node] == 2 && used[node] == 1) {
        for (auto e : v[node])
          if (!(e & 1) && c[e]) {
            taken[go[e]] = node;
            ++used[node];
            break;
          }
        assert(used[node] == 2);
      }
    int w;
    bool ok;
    for (node = N + 1; node <= N + M; ++node)
      if (taken[node]) {
        w = taken[node];
        if (w > D) {
          ok = 0;
          while (!ok) {
            assert(v[w].size());
            e = v[w][0];
            swap(v[w].front(), v[w].back());
            v[w].pop_back();
            if ((e & 1) && !c[e ^ 1]) {
              w = go[e];
              ok = 1;
            }
          }
        }
        cout << w << ' ' << node - N << '\n';
      }
  }
} graph;
void build_segm(int node, int st, int dr) {
  int i;
  for (i = st; i <= dr; ++i) graph.add_edge(node + D, N + i, 1);
  if (st == dr) {
    if (st == N) Nodes = node + D;
    return;
  }
  build_segm((node << 1), st, ((st + dr) >> 1));
  build_segm(((node << 1) | 1), ((st + dr) >> 1) + 1, dr);
}
void add_segm(int node, int st, int dr, int L, int R) {
  if (L <= st && dr <= R) {
    graph.add_edge(i, node + D, 1);
    return;
  }
  if (L <= ((st + dr) >> 1)) add_segm((node << 1), st, ((st + dr) >> 1), L, R);
  if (((st + dr) >> 1) < R)
    add_segm(((node << 1) | 1), ((st + dr) >> 1) + 1, dr, L, R);
}
int main() {
  cin.sync_with_stdio(false);
  cin >> N >> M;
  S = 0;
  D = N + M + 1;
  int tip, j, x, y;
  for (i = N + 1; i <= N + M; ++i) graph.add_edge(i, D, 1);
  build_segm(1, 1, M);
  for (i = 1; i <= N; ++i) {
    cin >> tip;
    if (tip == 0) {
      graph.add_edge(S, i, 1);
      cin >> K;
      for (j = 1; j <= K; ++j) {
        cin >> x;
        graph.add_edge(i, x + N, 1);
      }
    } else if (tip == 1) {
      graph.add_edge(S, i, 1);
      cin >> x >> y;
      add_segm(1, 1, M, x, y);
    } else if (tip == 2) {
      graph.add_edge(S, i, 2);
      for (j = 1; j <= 3; ++j) {
        cin >> x;
        graph.add_edge(i, x + N, 1);
      }
    }
    weapon[i] = tip;
  }
  cout << graph.max_flow() << '\n';
  graph.reconstruct();
  return 0;
}
