#include <bits/stdc++.h>
#pragma GCC optimize(3)
using namespace std;
const int inf = 0x3f3f3f3f;
const long long inf_ll = 0x3f3f3f3f3f3f3f3fLL;
const int maxn = 1e5 + 100;
vector<int> E[maxn];
vector<int> chain;
int color[maxn];
int vis[maxn];
int n;
bool in_chain[maxn];
pair<int, int> dp[maxn][2];
int pre[maxn];
stack<int> stk;
template <typename T, typename U>
pair<T, U> operator+(const pair<T, U> &x, const pair<T, U> &y) {
  return make_pair(x.first + y.first, x.second + y.second);
}
template <typename T, typename U>
pair<T, U> operator-(const pair<T, U> &x, const pair<T, U> &y) {
  return make_pair(x.first - y.first, x.second - y.second);
}
void dfs_dp(int u) {
  dp[u][0] = make_pair(0, 0);
  for (int v : E[u]) {
    if (in_chain[v]) continue;
    dfs_dp(v);
    dp[u][0] = dp[u][0] + max(dp[v][0], dp[v][1]);
  }
  dp[u][1] = dp[u][0];
  pair<int, int> max_del = make_pair(-inf, -inf);
  for (int v : E[u]) {
    if (in_chain[v]) continue;
    auto del = dp[v][0] - max(dp[v][0], dp[v][1]);
    del.first++;
    if (color[v] ^ color[u]) del.second++;
    if (del > max_del) {
      max_del = del;
      pre[u] = v;
    }
  }
  dp[u][1] = dp[u][1] + max_del;
}
void dfs_ans(int u, int flag, vector<pair<int, int> > &dp_ans) {
  for (int v : E[u]) {
    if (in_chain[v]) continue;
    if (flag == 1 && v == pre[u]) {
      dp_ans.push_back(make_pair(u, pre[u]));
      dfs_ans(v, 0, dp_ans);
    } else {
      if (dp[v][1] > dp[v][0]) {
        dfs_ans(v, 1, dp_ans);
      } else {
        dfs_ans(v, 0, dp_ans);
      }
    }
  }
}
void dfs(int u) {
  vis[u] = 1;
  stk.push(u);
  for (int v : E[u]) {
    if (!vis[v])
      dfs(v);
    else if (vis[v] == 2)
      continue;
    else if (vis[v] == 1) {
      while (1) {
        chain.push_back(stk.top());
        vis[stk.top()] = 2;
        stk.pop();
        if (chain.back() == v) break;
      }
      while (!stk.empty()) {
        vis[stk.top()] = 2;
        stk.pop();
      }
      reverse(chain.begin(), chain.end());
      for (int x : chain) in_chain[x] = 1;
      throw 1;
    } else
      assert(0);
  }
  vis[u] = 2;
  stk.pop();
}
vector<pair<int, int> > ans(0);
pair<int, int> DP[maxn][2];
bool used[maxn];
pair<pair<int, int>, vector<pair<int, int> > > dp_ans() {
  for (int x : chain) used[x] = 0;
  int pre = 0;
  for (int x : chain) {
    for (int i = 0; i < 2; i++) {
      DP[x][i] = max(DP[pre][0], DP[pre][1]) + dp[x][i];
    }
    if (pre) {
      pair<int, int> temp_dp =
          DP[pre][0] + dp[x][0] + make_pair(1, (int)(color[x] != color[pre]));
      if (temp_dp > DP[x][1]) {
        DP[x][1] = temp_dp;
        used[x] = 1;
      }
    }
    pre = x;
  }
  vector<pair<int, int> > mans(0);
  vector<int> chain = ::chain;
  int now, flag;
  int edp = chain.back();
  now = chain.back();
  if (DP[now][1] > DP[now][0])
    flag = 1;
  else
    flag = 0;
  chain.pop_back();
  if (flag == 1 && used[now])
    dfs_ans(now, 0, mans);
  else
    dfs_ans(now, flag, mans);
  while (!chain.empty()) {
    int tail = chain.back();
    chain.pop_back();
    if (flag == 1 && used[now]) {
      mans.push_back(make_pair(tail, now));
      now = tail;
      flag = 0;
    } else {
      if (DP[tail][1] > DP[tail][0])
        flag = 1;
      else
        flag = 0;
      now = tail;
    }
    if (flag == 1 && used[now])
      dfs_ans(now, 0, mans);
    else
      dfs_ans(now, flag, mans);
  }
  return make_pair(max(DP[edp][0], DP[edp][1]), mans);
}
pair<int, int> dp_out;
void work() {
  for (int root : chain) {
    dfs_dp(root);
  }
  pair<int, int> dp1;
  vector<pair<int, int> > ans1;
  tie(dp1, ans1) = dp_ans();
  int head = chain.front();
  reverse(chain.begin(), chain.end());
  chain.pop_back();
  reverse(chain.begin(), chain.end());
  chain.push_back(head);
  pair<int, int> dp2;
  vector<pair<int, int> > ans2;
  tie(dp2, ans2) = dp_ans();
  if (dp1 > dp2) {
    dp_out = dp_out + dp1;
    ans.insert(ans.end(), ans1.begin(), ans1.end());
  } else {
    dp_out = dp_out + dp2;
    ans.insert(ans.end(), ans2.begin(), ans2.end());
  }
}
void search_chain() {
  for (int i = 1; i <= n; i++) {
    if (!vis[i]) {
      while (!stk.empty()) stk.pop();
      try {
        dfs(i);
      } catch (int x) {
        work();
        chain.clear();
      }
    }
  }
}
int main() {
  cin >> n;
  for (int i = 1; i <= n; i++) {
    int v;
    cin >> v >> color[i];
    E[v].push_back(i);
  }
  search_chain();
  cout << dp_out.first << " " << dp_out.second << endl;
  for (auto pr : ans) {
    int u, v;
    tie(u, v) = pr;
    cout << v << " " << u << endl;
  }
  return 0;
}
