#include <bits/stdc++.h>
using namespace std;
int n, frb, flag;
int s[100005], u[100005], go[100005], bgo[100005];
int c, cnt, ccnt;
pair<int, int> dp[100005][2], res[100005][2];
pair<int, int> ans;
int ok[100005][2], vis[100005], way[100005][2];
vector<int> v[100005];
vector<pair<int, int> > p;
pair<int, int> best(pair<int, int> a, pair<int, int> b) {
  if (a.first > b.first) return a;
  if (a.first < b.first) return b;
  return (a.second > b.second ? a : b);
}
pair<int, int> add(pair<int, int> a, pair<int, int> b) {
  return {a.first + b.first, a.second + b.second};
}
pair<int, int> dec(pair<int, int> a, pair<int, int> b) {
  b = {-b.first, -b.second};
  return add(a, b);
}
void ret(int node, int w) {
  for (int i : v[node]) {
    if (vis[i] > 0) continue;
    if (w == 0 && bgo[node] == i) {
      p.push_back({i, node});
      ret(i, 1);
    } else {
      if (best(dp[i][0], dp[i][1]) == dp[i][0])
        ret(i, 0);
      else
        ret(i, 1);
    }
  }
}
void rec(int node, int c) {
  if (way[node][c]) {
    p.push_back({node, go[node]});
    ret(node, 1);
    ret(go[node], 1);
    if (go[go[node]] != frb) {
      rec(go[go[node]], c);
    }
  } else {
    if (best(dp[node][0], dp[node][1]) == dp[node][0]) {
      ret(node, 0);
    } else {
      ret(node, 1);
    }
    if (go[node] != frb) rec(go[node], c);
  }
}
pair<int, int> f(int node) {
  if (ok[node][c]) return res[node][c];
  ok[node][c] = 1;
  pair<int, int> r1;
  pair<int, int> r2 = {0, 0};
  if (go[node] == frb)
    r1 = best(dp[node][0], dp[node][1]);
  else
    r1 = add(f(go[node]), best(dp[node][0], dp[node][1]));
  if (go[node] != frb) {
    if (go[go[node]] == frb) {
      r2 = add(add(dp[node][1], dp[go[node]][1]), {1, s[node] != s[go[node]]});
    } else {
      r2 = add(f(go[go[node]]), add(add(dp[node][1], dp[go[node]][1]),
                                    {1, s[node] != s[go[node]]}));
    }
  }
  pair<int, int> r = best(r1, r2);
  if (r == r1) {
    way[node][c] = 0;
  } else {
    way[node][c] = 1;
  }
  return res[node][c] = r;
}
pair<int, int> solve(int beg) {
  frb = beg;
  pair<int, int> sol = f(beg);
  ++c;
  return sol;
}
void dfs2(int node) {
  pair<int, int> bc = {0, 0};
  int t = -1;
  for (int i : v[node]) {
    if (vis[i] > 0) continue;
    dfs2(i);
    pair<int, int> w = best(dp[i][0], dp[i][1]);
    dp[node][0] = add(dp[node][0], w);
    dp[node][1] = add(dp[node][1], w);
    pair<int, int> m = {dp[i][1].first + 1,
                        dp[i][1].second + (s[node] != s[i])};
    pair<int, int> f = dec(m, w);
    if (best(bc, f) == f) {
      bc = f;
      t = i;
    }
  }
  dp[node][0] = add(dp[node][0], bc);
  bgo[node] = t;
}
void dfs(int node) {
  if (vis[node]) {
    if (vis[node] == cnt) {
      flag = node;
      vis[node] = ++ccnt;
    }
    return;
  }
  vis[node] = cnt;
  dfs(go[node]);
  if (flag) vis[node] = ccnt;
  if (flag == node) flag = 0;
}
int main() {
  scanf("%d", &n);
  for (int i = 1; i <= n; i++) {
    int a, b;
    scanf("%d %d", &a, &b);
    go[i] = a;
    s[i] = b;
    v[a].push_back(i);
  }
  for (int i = 1; i <= n; i++) {
    if (vis[i]) continue;
    flag = 0;
    cnt--;
    dfs(i);
  }
  for (int i = 1; i <= n; i++) {
    if (vis[i] > 0) {
      dfs2(i);
    }
  }
  for (int i = 1; i <= n; i++) {
    if (vis[i] > 0 && !u[vis[i]]) {
      u[vis[i]] = 1;
      pair<int, int> a = solve(i);
      pair<int, int> b = solve(go[i]);
      pair<int, int> bs = best(a, b);
      ans = add(ans, bs);
      if (bs == a) {
        frb = i;
        rec(i, 0);
      } else {
        frb = go[i];
        rec(go[i], 1);
      }
      c = 0;
    }
  }
  printf("%d %d\n", ans.first, ans.second);
  for (auto x : p) printf("%d %d\n", x.first, x.second);
}
