#include <bits/stdc++.h>
using namespace std;
struct edge {
  short to, cap, rev;
  edge(int _a = 0, int _b = 0, int _c = 0) {
    to = _a;
    cap = _b;
    rev = _c;
  }
};
int S, T;
int dist[30010];
int cur[30010];
vector<edge> adj[30010];
int q[30010];
int hd, tl;
inline void addedge(int u, int v, int cap) {
  adj[u].push_back(edge(v, cap, adj[v].size()));
  adj[v].push_back(edge(u, 0, adj[u].size() - 1));
}
int dfs(int i, short fl) {
  if (i == T) return fl;
  short lf = fl;
  for (int &j = cur[i]; ~j; --j) {
    edge &e = adj[i][j];
    if (e.cap && dist[e.to] == dist[i] + 1) {
      short d = dfs(e.to, min(lf, e.cap));
      e.cap -= d;
      adj[e.to][e.rev].cap += d;
      lf -= d;
      if (!lf) return fl;
    }
  }
  dist[i] = -1;
  return fl - lf;
}
int Dinic() {
  int res = 0;
  while (true) {
    memset(dist, 0, sizeof(dist));
    dist[q[hd = tl = 0] = S] = 1;
    while (hd <= tl) {
      int i = q[hd++];
      cur[i] = adj[i].size() - 1;
      for (int j = cur[i]; ~j; --j) {
        edge &e = adj[i][j];
        if (e.cap && !dist[e.to]) {
          dist[e.to] = dist[i] + 1;
          q[++tl] = e.to;
        }
      }
    }
    if (!dist[T]) break;
    int fl;
    while (fl = dfs(S, 10000)) res += fl;
  }
  return res;
}
int bel[5010];
int tpe[5010];
int main(void) {
  int n, m;
  scanf("%d%d", &n, &m);
  S = 0;
  T = 30000;
  vector<pair<pair<int, int>, int> > v;
  for (int i = 1; i <= 8191; ++i) {
    addedge(n + i, n + (i << 1), 10000);
    addedge(n + i, n + (i << 1 | 1), 10000);
  }
  for (int i = 1; i <= n; ++i) {
    int a, b, c;
    scanf("%d%d", &tpe[i], &a);
    switch (tpe[i]) {
      case 0: {
        while (a--) {
          scanf("%d", &b);
          addedge(i, b + 8191 + n, 1);
        }
        break;
      }
      case 1: {
        scanf("%d", &b);
        v.push_back(make_pair(make_pair(a, b), i));
        int l = a + 8191, r = b + 8191;
        while (l <= r) {
          if (l & 1) addedge(i, n + l, 1), l++;
          if (!(r & 1)) addedge(i, n + r, 1), r--;
          l >>= 1;
          r >>= 1;
        }
        break;
      }
      case 2: {
        scanf("%d%d", &b, &c);
        addedge(i, a + 8191 + n, 1);
        addedge(i, b + 8191 + n, 1);
        addedge(i, c + 8191 + n, 1);
        break;
      }
    }
  }
  sort(v.begin(), v.end());
  for (int i = 1; i <= n; ++i) {
    if (tpe[i] != 2) {
      addedge(S, i, 1);
    }
  }
  for (int i = 1; i <= n; ++i) {
    if (tpe[i] == 2) {
      addedge(S, i, 2);
    }
  }
  for (int i = 1; i <= m; ++i) {
    addedge(n + 8191 + i, T, 1);
  }
  printf("%d\n", Dinic());
  for (int i = 1; i <= m; ++i) {
    for (int j = adj[i + 8191 + n].size() - 1; ~j; --j) {
      edge &e = adj[i + 8191 + n][j];
      if (e.cap && e.to != T) {
        bel[i] = e.to;
      }
    }
  }
  multiset<pair<pair<int, int>, int> > s;
  int pnt = 0, vs = v.size();
  for (int i = 1; i <= m; ++i) {
    if (bel[i] <= n && tpe[bel[i]] != 1) continue;
    while (pnt < vs && v[pnt].first.first <= i) {
      s.insert(make_pair(make_pair(v[pnt].first.second, v[pnt].first.first),
                         v[pnt].second));
      ++pnt;
    }
    while (!s.empty() && s.begin()->first.first < i) s.erase(s.begin());
    if (!s.empty()) bel[i] = s.begin()->second, s.erase(s.begin());
  }
  for (int i = 1; i <= m; ++i) {
    if (bel[i]) printf("%d %d\n", bel[i], i);
  }
  return 0;
}
