#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using ld = long double;
using pii = pair<int, int>;
const int N = 2e5 + 5, M = 998244353, INF = 0x3f3f3f3f;
void Main();
void print() { cout << '\n'; }
template <typename T, typename... U>
void print(const T& x, const U&... y) {
  ((sizeof...(y) == 0) ? (cout << x) : (cout << x << ' '));
  print(y...);
}
template <typename T>
void print(const T& a, int l, int r, char c) {
  for (int i = l; i <= r; ++i) {
    cout << a[i];
    if (i == r)
      cout << '\n';
    else
      cout << c;
  }
}
void input() {}
template <typename T, typename... U>
void input(T& x, U&... y) {
  cin >> x;
  input(y...);
}
template <typename T>
void input(T& a, int l, int r, bool f) {
  for (int i = l; i <= r; ++i) cin >> a[i];
}
template <typename T>
void Max(T& a, T b) {
  a < b ? a = b : 1;
}
template <typename T>
void Min(T& a, T b) {
  a > b ? a = b : 1;
}
template <typename T>
void Add(T& a, T b) {
  a += b, a > M ? a -= M : 1;
}
template <typename T>
void Mul(T& a, T b) {
  a = a * b % M;
}
int main(int argc, char** argv) {
  ios::sync_with_stdio(0), cin.tie(0);
  Main();
}
struct Dinic {
  struct edge {
    int from, to, cap, flow;
    edge(int u, int v, int c, int f) : from(u), to(v), cap(c), flow(f) {}
  };
  int n, m, s, t;
  vector<edge> edges;
  vector<int> G[N];
  int d[N], cur[N];
  bool vis[N];
  void init(int n) {
    for (int i = 0; i < n; i++) G[i].clear();
    edges.clear();
  }
  void add(int from, int to, int cap) {
    edges.push_back(edge(from, to, cap, 0));
    edges.push_back(edge(to, from, 0, 0));
    m = edges.size();
    G[from].push_back(m - 2);
    G[to].push_back(m - 1);
  }
  bool BFS() {
    memset(vis, 0, sizeof(vis));
    queue<int> Q;
    Q.push(s);
    d[s] = 0;
    vis[s] = 1;
    while (!Q.empty()) {
      int x = Q.front();
      Q.pop();
      for (int i = 0; i < G[x].size(); i++) {
        edge& e = edges[G[x][i]];
        if (!vis[e.to] && e.cap > e.flow) {
          vis[e.to] = 1;
          d[e.to] = d[x] + 1;
          Q.push(e.to);
        }
      }
    }
    return vis[t];
  }
  int DFS(int x, int a) {
    if (x == t || a == 0) return a;
    int flow = 0, f;
    for (int& i = cur[x]; i < G[x].size(); i++) {
      edge& e = edges[G[x][i]];
      if (d[x] + 1 == d[e.to] && (f = DFS(e.to, min(a, e.cap - e.flow))) > 0) {
        e.flow += f;
        edges[G[x][i] ^ 1].flow -= f;
        flow += f;
        a -= f;
        if (a == 0) break;
      }
    }
    return flow;
  }
  int maxflow(int s, int t) {
    this->s = s;
    this->t = t;
    int flow = 0;
    while (BFS()) {
      memset(cur, 0, sizeof(cur));
      flow += DFS(s, INF);
    }
    return flow;
  }
} D;
int tot, n, m, id[N << 2], L, R, now;
void build(int o, int l, int r) {
  if (l == r) {
    id[o] = ++tot;
    D.add(id[o], n + l, 1);
    return;
  }
  id[o] = ++tot;
  int mid = (l + r) / 2;
  build((o << 1), l, mid), build(((o << 1) | 1), mid + 1, r);
  D.add(id[o], id[(o << 1)], INF), D.add(id[o], id[((o << 1) | 1)], INF);
}
void update(int o, int l, int r) {
  if (l > R || r < L) return;
  if (L <= l && r <= R) {
    D.add(now, id[o], 1);
    return;
  }
  int mid = (l + r) / 2;
  update((o << 1), l, mid), update(((o << 1) | 1), mid + 1, r);
}
void dfs(int u, int fa, int& ans) {
  if (u <= n) {
    ans = u;
    return;
  }
  for (int i = (int)D.G[u].size() - 1; i >= 0; --i) {
    Dinic::edge& e = D.edges[D.G[u][i]];
    if (e.to && e.cap - e.flow > 0) {
      dfs(e.to, u, ans);
      --e.cap - e.flow;
      return;
    }
  }
}
int A[N], B[N], C[N], ans[N], num[N];
void Main() {
  input(n, m);
  tot = n + m;
  build(1, 1, m);
  const int S = tot + 1, T = tot + 2;
  for (int i = 1, op, k, x; i <= n; ++i) {
    input(op);
    if (op == 0) {
      D.add(S, i, 1);
      input(k);
      while (k--) {
        input(x);
        D.add(i, x + n, 1);
      }
    } else if (op == 1) {
      D.add(S, i, 1);
      input(L, R);
      now = i;
      update(1, 1, m);
    } else {
      D.add(S, i, 2);
      input(A[i], B[i], C[i]);
      D.add(i, A[i] + n, 1);
      D.add(i, B[i] + n, 1);
      D.add(i, C[i] + n, 1);
    }
  }
  for (int i = 1; i <= m; ++i) D.add(i + n, T, 1);
  print(D.maxflow(S, T));
  for (int i : D.G[T]) {
    Dinic::edge e = D.edges[i];
    if (e.cap - e.flow) dfs(e.to, T, ans[e.to - n]);
  }
  for (int i = 1; i <= m; ++i) ++num[ans[i]];
  for (int i = 1; i <= n; ++i)
    if (A[i] && num[i] == 1) {
      if (ans[A[i]] != i)
        ans[A[i]] = i;
      else
        ans[B[i]] = i;
    }
  for (int i = 1; i <= m; ++i)
    if (ans[i]) print(ans[i], i);
}
