#include <bits/stdc++.h>
using namespace std;
const int MAXN = 100010, BIG = 314000000, INF = 0x3f3f3f3f;
int N, M;
vector<int> gone;
vector<int> toR[MAXN], fromR[MAXN];
struct rule {
  int start, diamonds;
  vector<int> end;
};
rule R[MAXN];
int smallest[MAXN], largest[MAXN];
void dijkstra(int* arr, int mult) {
  static bool v[MAXN];
  memset(v, false, sizeof(v));
  priority_queue<pair<pair<int, int>, int> > pq;
  for (int i = 0; i < gone.size(); i++) {
    pq.push(make_pair(make_pair(mult * R[gone[i]].diamonds, R[gone[i]].start),
                      gone[i]));
  }
  while (!pq.empty()) {
    pair<pair<int, int>, int> top = pq.top();
    pq.pop();
    if (v[top.second]) continue;
    v[top.second] = true;
    if (arr[top.first.second] == -1 ||
        arr[top.first.second] * mult < top.first.first)
      arr[top.first.second] = mult * top.first.first;
    for (int i = 0; i < fromR[top.first.second].size(); i++) {
      if (!v[fromR[top.first.second][i]]) {
        bool good = true;
        int cost = R[fromR[top.first.second][i]].diamonds;
        vector<int>& those = R[fromR[top.first.second][i]].end;
        for (int j = 0; good && j < those.size(); j++) {
          if (arr[those[j]] != -1)
            cost = min(BIG, cost + arr[those[j]]);
          else
            good = false;
        }
        if (good) {
          pq.push(make_pair(
              make_pair(mult * cost, R[fromR[top.first.second][i]].start),
              fromR[top.first.second][i]));
        }
      }
    }
  }
}
bool v[MAXN], at[MAXN], can[MAXN];
void make_smallest() {
  memset(smallest, -1, sizeof(smallest));
  dijkstra(smallest, -1);
}
void dfs(int x) {
  if (at[x]) {
    can[x] = true;
    return;
  }
  if (v[x]) return;
  v[x] = true;
  at[x] = true;
  for (int i = 0; !can[x] && i < toR[x].size(); i++) {
    vector<int>& those = R[toR[x][i]].end;
    bool allok = true;
    for (int j = 0; j < those.size(); j++) {
      if (smallest[those[j]] == -1) allok = false;
      dfs(those[j]);
      if (can[those[j]]) can[x] = true;
    }
    if (!allok) can[x] = false;
  }
  at[x] = false;
}
int find_max(int x) {
  if (largest[x] != -1) return largest[x];
  if (at[x] || smallest[x] == -1) return largest[x] = -2;
  at[x] = true;
  int ret = 0;
  for (int i = 0; i < toR[x].size(); i++) {
    bool allok = true;
    int sum = R[toR[x][i]].diamonds;
    vector<int>& those = R[toR[x][i]].end;
    for (int i = 0; i < those.size(); i++) {
      int m = find_max(those[i]);
      if (m < 0) allok = false;
      sum = min(sum + m, BIG);
    }
    if (allok) ret = max(ret, sum);
  }
  at[x] = false;
  return largest[x] = ret;
}
void make_largest() {
  memset(largest, -1, sizeof(largest));
  for (int i = 0; i < N; i++) dfs(i);
  for (int i = 0; i < N; i++)
    if (can[i]) largest[i] = -2;
  for (int i = 0; i < N; i++) find_max(i);
}
int main() {
  cin >> M >> N;
  for (int i = 0; i < M; i++) {
    int l;
    cin >> R[i].start >> l;
    R[i].start--;
    R[i].diamonds = 0;
    for (int j = 0; j < l; j++) {
      int a;
      cin >> a;
      if (a == -1)
        R[i].diamonds++;
      else
        R[i].end.push_back(a - 1);
      fromR[a - 1].push_back(i);
    }
    toR[R[i].start].push_back(i);
    if (R[i].diamonds == l) gone.push_back(i);
  }
  make_smallest();
  make_largest();
  for (int i = 0; i < N; i++) {
    if (smallest[i] == -1)
      cout << "-1 -1\n";
    else
      cout << smallest[i] << ' ' << largest[i] << '\n';
  }
  return 0;
}
