#include <bits/stdc++.h>
using namespace std;
char gc() {
  static char buf[100000], *p1 = buf, *p2 = buf;
  return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 100000, stdin), p1 == p2)
             ? EOF
             : *p1++;
}
inline int read() {
  int x = 0, f = 1;
  char ch = getchar();
  while (ch < '0' || ch > '9') {
    if (ch == '-') f = -1;
    ch = getchar();
  }
  while (ch >= '0' && ch <= '9')
    x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
  return x * f;
}
inline long long readll() {
  long long x = 0, f = 1;
  char ch = getchar();
  while (ch < '0' || ch > '9') {
    if (ch == '-') f = -1;
    ch = getchar();
  }
  while (ch >= '0' && ch <= '9')
    x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
  return x * f;
}
inline void write(int x) {
  if (!x) putchar('0');
  if (x < 0) x = -x, putchar('-');
  static int sta[20];
  register int tot = 0;
  while (x) sta[tot++] = x % 10, x /= 10;
  while (tot) putchar(sta[--tot] + 48);
}
const int maxn = 200007, INF = 0x3f3f3f3f;
const int MOD = 998244353;
const long long LINF = 0x3f3f3f3f3f3f3f3fll;
const long long P = 19260817;
inline int mod1(int x) { return x < MOD ? x : x - MOD; }
inline int mod2(int x) { return x < 0 ? x + MOD : x; }
inline void add(int &x, int y) { x = mod1(x + y); }
inline void sub(int &x, int y) { x = mod2(x - y); }
inline int checkmax(pair<int, int> &x, pair<int, int> y) {
  if (x < y) return x = y, 1;
  return 0;
}
int n;
struct edge {
  int to, nxt;
} e[maxn << 1];
int head[maxn], tot;
pair<int, int> ans, dp[maxn][2];
void addedge(int u, int v) {
  e[++tot] = (edge){v, head[u]};
  head[u] = tot;
}
int rt;
int f[maxn], s[maxn];
int vis[maxn];
pair<int, int> operator+(const pair<int, int> &x, const pair<int, int> &y) {
  return make_pair(x.first + y.first, x.second + y.second);
}
pair<int, int> operator-(const pair<int, int> &x, const pair<int, int> &y) {
  return make_pair(x.first - y.first, x.second - y.second);
}
int from[maxn];
void dfs1(int u) {
  dp[u][0] = dp[u][1] = make_pair(0, 0);
  vis[u] = 1;
  from[u] = 0;
  pair<int, int> res = make_pair(0, 0);
  for (int i = head[u]; i; i = e[i].nxt) {
    int v = e[i].to;
    if (v == rt) continue;
    dfs1(v);
    dp[u][1] = dp[u][1] + dp[v][0];
    if (checkmax(res, dp[v][1] + make_pair(1, s[u] != s[v]) - dp[v][0]))
      from[u] = v;
  }
  dp[u][0] = dp[u][1] + res;
}
vector<pair<int, int> > tmp, vec;
void dfs2(int u, int flag) {
  for (int i = head[u]; i; i = e[i].nxt) {
    int v = e[i].to;
    if (v == rt) continue;
    if (flag)
      dfs2(v, 0);
    else if (from[u] == v)
      tmp.push_back(make_pair(u, v)), dfs2(v, 1);
    else
      dfs2(v, 0);
  }
}
void solve(int u) {
  while (!vis[u]) {
    vis[u] = 1;
    u = f[u];
  }
  pair<int, int> res = make_pair(0, 0);
  rt = u;
  dfs1(rt);
  if (checkmax(res, dp[rt][0])) tmp.clear(), dfs2(rt, 0);
  rt = f[u];
  dfs1(rt);
  if (checkmax(res, dp[rt][0])) tmp.clear(), dfs2(rt, 0);
  ans = ans + res;
  for (auto x : tmp) {
    vec.push_back(x);
  }
}
int main() {
  scanf("%d", &n);
  for (int i = 1; i <= n; i++) {
    scanf("%d%d", &f[i], &s[i]);
    addedge(f[i], i);
  }
  for (int i = 1; i <= n; i++) {
    if (!vis[i]) solve(i);
  }
  printf("%d %d\n", ans.first, ans.second);
  for (auto x : vec) printf("%d %d\n", x.first, x.second);
  return 0;
}
