#include <bits/stdc++.h>
using namespace std;
using namespace std::rel_ops;
const int N = 100050, inf = ~0u >> 2;
struct state {
  int c, sc;
  static state minimal() { return (state){-inf, -inf}; }
  state(int x = 0, int y = 0) : c(x), sc(y) {}
};
state operator+(state a, state b) { return (state){a.c + b.c, a.sc + b.sc}; }
state operator-(state a, state b) { return (state){a.c - b.c, a.sc - b.sc}; }
bool operator<(state a, state b) {
  return a.c < b.c || (a.c == b.c && a.sc < b.sc);
}
bool operator>(state a, state b) {
  return a.c > b.c || (a.c == b.c && a.sc > b.sc);
}
bool operator==(state a, state b) { return a.c == b.c && a.sc == b.sc; }
state dp[N][2];
int pal[N][2], gender[N], invalid[N], n;
vector<int> e[N];
vector<int> ring;
vector<pair<int, int> > reslist;
int pre[N], vis[N], sel[N];
bool findRing(int x, int ax) {
  if (vis[x]) {
    for (int y = ax; y != pre[x]; y = pre[y]) invalid[y] = 1, ring.push_back(y);
    return true;
  }
  vis[x] = true;
  pre[x] = ax;
  bool res = false;
  for (int y : e[x])
    if (y != ax && !invalid[y] && findRing(y, x))
      res = true;
    else if (y == ax)
      ax = -1;
  return res;
}
void dfs(int x, int ax) {
  state mdel = state::minimal(), cdel;
  int z = 0;
  for (int y : e[x])
    if (!invalid[y] && y != ax) {
      dfs(y, x);
      dp[x][1] = dp[x][1] + max(dp[y][1], dp[y][0]);
      dp[x][0] = dp[x][0] + max(dp[y][1], dp[y][0]);
      cdel =
          dp[y][1] - max(dp[y][1], dp[y][0]) + state(1, gender[y] != gender[x]);
      if (cdel > mdel) mdel = cdel, z = y;
    }
  if (mdel != state::minimal()) {
    dp[x][0] = dp[x][0] + mdel;
    pal[x][0] = z;
  }
}
void tgenerate(int x, int ax, int cp) {
  if (!cp && pal[x][0]) reslist.push_back(make_pair(x, pal[x][0]));
  for (int y : e[x])
    if (y != ax && !invalid[y])
      if (!cp && y == pal[x][0])
        tgenerate(y, x, 1);
      else
        tgenerate(y, x, dp[y][1] >= dp[y][0]);
}
state dpRing(int l, int r, bool gen = false) {
  static state dp[N][2];
  if (l > r) return (state){0, 0};
  dp[ring[l]][0] = ::dp[ring[l]][0];
  dp[ring[l]][1] = ::dp[ring[l]][1];
  for (int i = l; i + 1 <= r; ++i) {
    int x = ring[i], y = ring[i + 1];
    dp[y][0] = ::dp[y][0];
    dp[y][1] = ::dp[y][1];
    state a = dp[y][0] + max(dp[x][0], dp[x][1]),
          b = dp[y][1] + dp[x][1] + state(1, gender[y] != gender[x]);
    dp[y][0] = max(a, b);
    if (gen) pal[y][0] = (dp[y][0] == a) ? pal[y][0] : x;
    dp[y][1] = max(dp[x][0], dp[x][1]) + dp[y][1];
  }
  state a = dp[ring[r]][0], b = dp[ring[r]][1];
  if (!gen) return max(a, b);
  for (int i = r, cp = (a > b ? 0 : 1); i >= l; --i)
    if (cp == 0 && i != l && pal[ring[i]][cp] == ring[i - 1]) {
      reslist.push_back(make_pair(ring[i], ring[i - 1]));
      tgenerate(ring[i], 0, 1);
      cp = 1;
    } else {
      tgenerate(ring[i], 0, cp);
      if (i != l) cp = dp[ring[i - 1]][0] < dp[ring[i - 1]][1];
    }
  return max(a, b);
}
inline state solveRing(int u) {
  ring.clear();
  if (!findRing(u, 0) || ring.size() == 1) throw;
  for (int y : ring) dfs(y, 0);
  int f = ring.front(), r = ring.back();
  state res1 = dpRing(0, ring.size() - 1), res2,
        cd2 = (state){1, gender[f] != gender[r]} + dp[f][1] + dp[r][1];
  res2 = dpRing(1, ring.size() - 2) + cd2;
  if (res1 > res2) {
    dpRing(0, ring.size() - 1, true);
    return res1;
  } else {
    dpRing(1, ring.size() - 2, true);
    reslist.push_back(make_pair(f, r));
    tgenerate(f, 0, 1);
    tgenerate(r, 0, 1);
    return res2;
  }
}
int main() {
  scanf("%d", &n);
  for (int i = 1, a; i <= n; ++i) {
    scanf("%d%d", &a, gender + i);
    e[a].push_back(i);
    e[i].push_back(a);
  }
  state res = (state){0, 0};
  for (int u = 1; u <= n; ++u) {
    if (vis[u]) continue;
    res = res + solveRing(u);
  }
  printf("%d %d\n", res.c, res.sc);
  if (reslist.size() != res.c) throw;
  for (auto r : reslist) printf("%d %d\n", r.first, r.second);
  return 0;
}
