#include <bits/stdc++.h>
using namespace std;
template <class T>
inline void checkmin(T &a, const T &b) {
  if (b < a) a = b;
}
template <class T>
inline void checkmax(T &a, const T &b) {
  if (b > a) a = b;
}
const int maxn = 1e5 + 10;
pair<int, int> dp[maxn][2];
int match[maxn];
vector<pair<int, int> > g[maxn], track;
int n, s[maxn], dep[maxn];
vector<int> v;
map<pair<int, int>, bool> Map;
pair<int, int> operator+(const pair<int, int> &a, const pair<int, int> &b) {
  return make_pair(a.first + b.first, a.second + b.second);
}
pair<int, int> operator-(const pair<int, int> &a, const pair<int, int> &b) {
  return make_pair(a.first - b.first, a.second - b.second);
}
pair<int, int> dfs(int x, int fa) {
  v.push_back(x);
  pair<int, int> res = make_pair(-1, -1);
  for (int i = 0; i < (int)g[x].size(); i++) {
    int to = g[x][i].first, id = g[x][i].second;
    if (to == fa) continue;
    if (dep[to] != -1) {
      if (res.first >= 0) continue;
      for (int j = 0; j < (int)g[x].size(); j++) {
        if (g[x][j].first == fa) {
          res.first = g[x][j].second;
          break;
        }
      }
      res.second = id;
    } else {
      dep[to] = dep[x] + 1;
      pair<int, int> tmp = dfs(to, x);
      if (tmp.first >= 0 && res.first < 0) res = tmp;
    }
  }
  return res;
}
void get_ans(int x, int fa, int cut) {
  pair<int, int> sum;
  for (int i = 0; i < (int)g[x].size(); i++) {
    int to = g[x][i].first, id = g[x][i].second;
    if (to == fa || id == cut) continue;
    get_ans(to, x, cut);
    sum = sum + max(dp[to][0], dp[to][1]);
  }
  dp[x][0] = sum;
  for (int i = 0; i < (int)g[x].size(); i++) {
    int to = g[x][i].first, id = g[x][i].second;
    if (to == fa || id == cut) continue;
    pair<int, int> tmp = make_pair(1, s[to] != s[x]);
    if (dp[to][0] + sum - max(dp[to][0], dp[to][1]) + tmp > dp[x][1]) {
      dp[x][1] = dp[to][0] + sum - max(dp[to][0], dp[to][1]) + tmp;
      match[x] = to;
    }
  }
}
void get_track(int x, int fa, int type, int cut) {
  for (int i = 0; i < (int)g[x].size(); i++) {
    int to = g[x][i].first, id = g[x][i].second;
    if (to == fa || cut == id) continue;
    if ((type == 0) || (type == 1 && match[x] != to)) {
      get_track(to, x, dp[to][0] > dp[to][1] ? 0 : 1, cut);
    } else {
      track.push_back(make_pair(x, to));
      get_track(to, x, 0, cut);
    }
  }
}
int main() {
  cin >> n;
  for (int i = 0; i < n; i++) {
    int to;
    cin >> to >> s[i];
    s[i]--;
    to--;
    if (Map.find(make_pair(to, i)) != Map.end()) continue;
    Map[make_pair(to, i)] = Map[make_pair(i, to)] = true;
    g[to].push_back(make_pair(i, i));
    g[i].push_back(make_pair(to, i));
  }
  for (int i = 0; i < maxn; i++) {
    match[i] = dep[i] = -1;
  }
  pair<int, int> ans = make_pair(0, 0);
  for (int i = 0; i < n; i++) {
    if (dep[i] == -1) {
      v.clear();
      dep[i] = 0;
      pair<int, int> res = dfs(i, -1);
      if (res.first == -1) {
        get_ans(i, -1, -1);
        ans = ans + max(dp[i][0], dp[i][1]);
        get_track(i, -1, dp[i][0] > dp[i][1] ? 0 : 1, -1);
      } else {
        pair<int, int> tmp1, tmp2;
        get_ans(i, -1, res.first);
        tmp1 = max(dp[i][0], dp[i][1]);
        for (int j = 0; j < (int)v.size(); j++) {
          dp[v[j]][0] = dp[v[j]][1] = make_pair(0, 0);
          match[v[j]] = false;
        }
        get_ans(i, -1, res.second);
        tmp2 = max(dp[i][0], dp[i][1]);
        if (tmp1 > tmp2) {
          for (int j = 0; j < (int)v.size(); j++) {
            dp[v[j]][0] = dp[v[j]][1] = make_pair(0, 0);
            match[v[j]] = false;
          }
          get_ans(i, -1, res.first);
          get_track(i, -1, dp[i][0] > dp[i][1] ? 0 : 1, res.first);
        } else {
          get_track(i, -1, dp[i][0] > dp[i][1] ? 0 : 1, res.second);
        }
        ans = ans + max(tmp1, tmp2);
      }
    }
  }
  cout << ans.first << " " << ans.second << endl;
  for (int i = 0; i < (int)track.size(); i++) {
    cout << track[i].first + 1 << " " << track[i].second + 1 << endl;
  }
  return 0;
}
