#include <bits/stdc++.h>
using namespace std;
int n, num = 1, fst[100010], gen[100010], from[100010], pre[100010],
       gp[100010][2];
struct edge {
  int x, y, n;
} e[200010];
bool tf[100010], oncir[100010], v[100010];
pair<int, int> f[100010][2], g[100010][2], ans(0, 0);
vector<pair<int, int> > anse;
pair<int, int> operator+(pair<int, int> x, pair<int, int> y) {
  return make_pair(x.first + y.first, x.second + y.second);
}
pair<int, int> operator-(pair<int, int> x, pair<int, int> y) {
  return make_pair(x.first - y.first, x.second - y.second);
}
pair<int, int> &operator+=(pair<int, int> &x, pair<int, int> y) {
  return x = x + y;
}
void ins(int x, int y) {
  e[++num] = {x, y, fst[x]};
  fst[x] = num;
}
void mark(int x) {
  tf[x] = 1;
  for (int i = fst[x]; i; i = e[i].n) {
    int y = e[i].y;
    if (tf[y]) continue;
    mark(y);
  }
}
bool dfs(int x, int f, vector<int> &cir) {
  v[x] = 1;
  for (int i = fst[x]; i; i = e[i].n) {
    if (i == (f ^ 1)) continue;
    int y = e[i].y;
    if (v[y]) {
      int hh = x;
      while (x != y) {
        cir.push_back(x);
        oncir[x] = 1;
        x = from[x];
      }
      cir.push_back(y);
      oncir[y] = 1;
      return 1;
    }
    from[y] = x;
    if (dfs(y, i, cir)) return 1;
  }
  return 0;
}
void dp(int x, int fa) {
  f[x][0] = f[x][1] = {0, 0};
  for (int i = fst[x]; i; i = e[i].n) {
    int y = e[i].y;
    if (y == fa || oncir[y]) continue;
    dp(y, x);
    f[x][0] += max(f[y][0], f[y][1]);
  }
  for (int i = fst[x]; i; i = e[i].n) {
    int y = e[i].y;
    if (y == fa || oncir[y]) continue;
    pair<int, int> hh = f[x][0] - max(f[y][0], f[y][1]) + f[y][0] +
                        make_pair(1, gen[x] != gen[y]);
    if (hh > f[x][1]) {
      pre[x] = y;
      f[x][1] = hh;
    }
  }
}
void clr_g(int size) {
  for (int i = 0; i < size; i++) {
    g[i][0] = g[i][1] = make_pair(1, 1);
    gp[i][0] = gp[i][1] = -1;
  }
}
void get(int x, int fa, int type, vector<pair<int, int> > &anse) {
  if (type) anse.emplace_back(x, pre[x]);
  for (int i = fst[x]; i; i = e[i].n) {
    int y = e[i].y;
    if (y == fa || oncir[y]) continue;
    if (type && y == pre[x])
      get(y, x, 0, anse);
    else
      get(y, x, f[y][0] < f[y][1], anse);
  }
}
void path(vector<pair<int, int> > &tmp, vector<int> &cir, int type, bool tf) {
  for (int i = cir.size() - 1; i > 0; i--) {
    if (!type) {
      get(cir[i], 0, 0, tmp);
      type = g[i - 1][0] < g[i - 1][1];
    } else {
      if (max(g[i - 1][0], g[i - 1][1]) + f[cir[i]][1] >
          g[i - 1][0] + f[cir[i]][0] +
              make_pair(1, gen[cir[i]] != gen[cir[i - 1]])) {
        get(cir[i], 0, 1, tmp);
        type = g[i - 1][0] < g[i - 1][1];
      } else {
        tmp.emplace_back(cir[i], cir[i - 1]);
        get(cir[i], 0, 0, tmp);
        type = 0;
      }
    }
  }
  if (tf)
    get(cir[0], 0, type, tmp);
  else
    get(cir[0], 0, 0, tmp);
}
void wk(int x) {
  mark(x);
  vector<int> cir;
  dfs(x, 0, cir);
  for (int x : cir) dp(x, 0);
  clr_g(cir.size());
  g[0][0] = f[cir[0]][0];
  g[0][1] = f[cir[0]][1];
  for (int i = 1; i < cir.size(); i++) {
    g[i][0] = max(g[i - 1][0], g[i - 1][1]) + f[cir[i]][0];
    g[i][1] = max(max(g[i - 1][0], g[i - 1][1]) + f[cir[i]][1],
                  g[i - 1][0] + f[cir[i]][0] +
                      make_pair(1, gen[cir[i]] != gen[cir[i - 1]]));
  }
  pair<int, int> s = max(g[cir.size() - 1][0], g[cir.size() - 1][1]);
  vector<pair<int, int> > tmp;
  int type = g[cir.size() - 1][0] < g[cir.size() - 1][1];
  path(tmp, cir, type, 1);
  clr_g(cir.size());
  g[0][0] = make_pair(-0x3f3f3f3f, 0);
  g[0][1] = make_pair(1, gen[cir[0]] != gen[cir.back()]) + f[cir[0]][0];
  for (int i = 1; i < cir.size(); i++) {
    g[i][0] = max(g[i - 1][0], g[i - 1][1]) + f[cir[i]][0];
    g[i][1] = max(max(g[i - 1][0], g[i - 1][1]) + f[cir[i]][1],
                  g[i - 1][0] + f[cir[i]][0] +
                      make_pair(1, gen[cir[i]] != gen[cir[i - 1]]));
  }
  if (g[cir.size() - 1][0] > s) {
    s = g[cir.size() - 1][0];
    tmp.clear();
    type = 0;
    path(tmp, cir, type, 0);
    tmp.emplace_back(cir[0], cir.back());
  }
  ans += s;
  for (pair<int, int> x : tmp) anse.push_back(x);
}
int main() {
  scanf("%d", &n);
  for (int i = 1; i <= n; i++) {
    int x;
    scanf("%d%d", &x, &gen[i]);
    ins(i, x);
    ins(x, i);
  }
  for (int i = 1; i <= n; i++)
    if (!tf[i]) wk(i);
  printf("%d %d\n", ans.first, ans.second);
  for (pair<int, int> x : anse) printf("%d %d\n", x.first, x.second);
}
