#include <bits/stdc++.h>
int a, b, c, d, e, f, g[100005], h[100005], i, j;
int F[100005][2], G[100005][2];
struct node {
  int u, v, w, next;
};
struct node map[300005];
struct node Pair[300005];
int tot;
int end[100005];
struct node1 {
  int x, from;
};
struct node1 cir[100005];
int dfn[100005];
int father[100005];
int from[100005];
int ok;
int v[300005];
int an, an1;
int in[300005];
int an2;
int AN, AN1;
int vv[100005];
int que[100005];
int l, r;
void set(int u, int v, int w) {
  map[++e].v = v;
  map[e].w = w;
  map[e].next = end[u];
  end[u] = e;
}
int Max(int x, int y) {
  if (x > y) return x;
  return y;
}
int Pair_Edge(int x) {
  if (x & 1) return x + 1;
  return x - 1;
}
void Find_Cir(int x) {
  int ii, jj, kk;
  dfn[x] = ++d;
  kk = 0;
  jj = end[x];
  while (jj) {
    if (map[jj].v != father[x]) {
      if (dfn[map[jj].v] != 0 && dfn[map[jj].v] < dfn[x]) {
        for (ii = x; ii != map[jj].v; ii = father[ii]) {
          cir[++b].x = ii;
          cir[b].from = from[ii];
        }
        cir[++b].x = map[jj].v;
        cir[b].from = jj;
        ok = 1;
        return;
      }
      if (dfn[map[jj].v] == 0) {
        from[map[jj].v] = jj;
        father[map[jj].v] = x;
        Find_Cir(map[jj].v);
      }
    } else
      kk++;
    if (map[jj].v == father[x] && kk == 2) {
      for (ii = x; ii != map[jj].v; ii = father[ii]) {
        cir[++b].x = ii;
        cir[b].from = from[ii];
      }
      cir[++b].x = map[jj].v;
      cir[b].from = jj;
    }
    jj = map[jj].next;
  }
}
void DP(int x) {
  int ii, jj, kk;
  int T1, T2;
  vv[x] = 1;
  jj = end[x];
  while (jj) {
    if (v[jj] == 0 && map[jj].v != father[x]) {
      father[map[jj].v] = x;
      DP(map[jj].v);
      if (F[map[jj].v][1] > F[map[jj].v][0] ||
          (F[map[jj].v][1] == F[map[jj].v][0] &&
           G[map[jj].v][1] > G[map[jj].v][0])) {
        F[x][0] += F[map[jj].v][1];
        G[x][0] += G[map[jj].v][1];
      } else {
        F[x][0] += F[map[jj].v][0];
        G[x][0] += G[map[jj].v][0];
      }
    }
    jj = map[jj].next;
  }
  jj = end[x];
  while (jj) {
    if (v[jj] == 0 && map[jj].v != father[x]) {
      if (F[map[jj].v][1] > F[map[jj].v][0] ||
          (F[map[jj].v][1] == F[map[jj].v][0] &&
           G[map[jj].v][1] > G[map[jj].v][0])) {
        T1 = F[x][0] - F[map[jj].v][1];
        T2 = G[x][0] - G[map[jj].v][1];
      } else {
        T1 = F[x][0] - F[map[jj].v][0];
        T2 = G[x][0] - G[map[jj].v][0];
      }
      T1 += F[map[jj].v][0] + 1;
      T2 += G[map[jj].v][0] + map[jj].w;
      if (T1 > F[x][1] || (T1 == F[x][1] && T2 > G[x][1])) {
        in[x] = map[jj].v;
        F[x][1] = T1;
        G[x][1] = T2;
      }
    }
    jj = map[jj].next;
  }
}
void soso(int x) {
  int ii, jj, kk;
  que[++r] = x;
  jj = end[x];
  while (jj) {
    if (v[jj] == 0 && map[jj].v != father[x]) {
      father[map[jj].v] = x;
      soso(map[jj].v);
    }
    jj = map[jj].next;
  }
}
void Print(int x, int y) {
  int ii, jj, kk;
  if (y == 1) {
    Pair[++tot].u = x;
    Pair[tot].v = in[x];
  }
  jj = end[x];
  while (jj) {
    if (v[jj] == 0 && map[jj].v != father[x] &&
        (y == 0 || (y == 1 && map[jj].v != in[x]))) {
      father[map[jj].v] = x;
      if (F[map[jj].v][1] > F[map[jj].v][0] ||
          (F[map[jj].v][1] == F[map[jj].v][0] &&
           G[map[jj].v][1] > G[map[jj].v][0])) {
        Print(map[jj].v, 1);
      } else {
        Print(map[jj].v, 0);
      }
    }
    if (v[jj] == 0 && y == 1 && map[jj].v == in[x]) {
      Print(map[jj].v, 0);
    }
    jj = map[jj].next;
  }
}
int Min(int x, int y) {
  if (x < y) return x;
  return y;
}
int main() {
  scanf("%d", &a);
  for (i = 1; i <= a; i++) scanf("%d%d", &g[i], &h[i]);
  for (i = 1; i <= a; i++) {
    set(i, g[i], h[i] != h[g[i]]);
    set(g[i], i, h[i] != h[g[i]]);
  }
  l = 1;
  for (c = 1; c <= a; c++)
    if (vv[c] == 0) {
      b = 0;
      Find_Cir(c);
      if (cir[1].from != 0) {
        v[cir[1].from] = 1;
        v[Pair_Edge(cir[1].from)] = 1;
      }
      soso(c);
      if (cir[1].from != 0) {
        v[cir[1].from] = 0;
        v[Pair_Edge(cir[1].from)] = 0;
      }
      an = -(1 << 30);
      for (i = 1; i <= Min(3, b); i++) {
        if (cir[i].from != 0) {
          v[cir[i].from] = 1;
          v[Pair_Edge(cir[i].from)] = 1;
        }
        for (j = l; j <= r; j++) {
          father[que[j]] = 0;
          F[que[j]][0] = 0;
          G[que[j]][0] = 0;
          F[que[j]][1] = 0;
          G[que[j]][1] = 0;
        }
        DP(c);
        if (F[c][0] > an || (F[c][0] == an && G[c][0] > an1)) {
          an = F[c][0];
          an1 = G[c][0];
          an2 = i;
        }
        if (F[c][1] > an || (F[c][1] == an && G[c][1] > an1)) {
          an = F[c][1];
          an1 = G[c][1];
          an2 = i;
        }
        if (cir[i].from != 0) {
          v[cir[i].from] = 0;
          v[Pair_Edge(cir[i].from)] = 0;
        }
      }
      i = an2;
      if (cir[i].from != 0) {
        v[cir[i].from] = 1;
        v[Pair_Edge(cir[i].from)] = 1;
      }
      for (j = l; j <= r; j++) {
        father[que[j]] = 0;
        F[que[j]][0] = 0;
        G[que[j]][0] = 0;
        F[que[j]][1] = 0;
        G[que[j]][1] = 0;
      }
      DP(c);
      an = -5;
      if (F[c][0] > an || (F[c][0] == an && G[c][0] > an1)) {
        an = F[c][0];
        an1 = G[c][0];
        an2 = 0;
      }
      if (F[c][1] > an || (F[c][1] == an && G[c][1] > an1)) {
        an = F[c][1];
        an1 = G[c][1];
        an2 = 1;
      }
      Print(c, an2);
      AN += an;
      AN1 += an1;
      l = r + 1;
    }
  printf("%d %d\n", AN, AN1);
  for (i = 1; i <= tot; i++) printf("%d %d\n", Pair[i].u, Pair[i].v);
  return 0;
}
