#include <bits/stdc++.h>
using namespace std;
inline 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);
}
inline 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);
}
inline pair<int, int> operator+=(pair<int, int> &x, const pair<int, int> &y) {
  x.first += y.first;
  x.second += y.second;
  return x;
}
inline bool operator<(const pair<int, int> &x, const pair<int, int> &y) {
  return (x.first < y.first || (x.first == y.first && x.second < y.second));
}
int n;
const int MAXN = 100005;
int f[MAXN], type[MAXN];
bool vis[MAXN];
bool incyc[MAXN];
vector<int> G[MAXN];
pair<int, int> dp[MAXN][2];
int who[MAXN];
int anc;
inline void dfsDP(int u, int pa) {
  vis[u] = 1;
  dp[u][0] = dp[u][1] = make_pair(0, 0);
  pair<int, int> best = make_pair(0, 0);
  for (int i = 0; i < G[u].size(); ++i) {
    int v = G[u][i];
    if (v == pa || v == anc) continue;
    dfsDP(v, u);
    dp[u][0] += dp[v][1];
    if (best < dp[v][0] - dp[v][1] + make_pair(1, type[u] ^ type[v])) {
      best = dp[v][0] - dp[v][1] + make_pair(1, type[u] ^ type[v]);
      who[u] = v;
    }
  }
  dp[u][1] = dp[u][0] + best;
}
vector<pair<int, int> > res, vec;
inline void dfsPath(int u, int pa, int cho) {
  if (!cho || dp[u][0] == dp[u][1]) {
    for (int i = 0; i < G[u].size(); ++i) {
      int v = G[u][i];
      if (v == pa || v == anc) continue;
      dfsPath(v, u, 1);
    }
  } else {
    vec.push_back(make_pair(u, who[u]));
    for (int i = 0; i < G[u].size(); ++i) {
      int v = G[u][i];
      if (v == pa || v == anc) continue;
      if (v == who[u])
        dfsPath(v, u, 0);
      else
        dfsPath(v, u, 1);
    }
  }
}
pair<int, int> ans = make_pair(0, 0);
int main() {
  ios::sync_with_stdio(false);
  cin >> n;
  for (int i = 1; i <= (n); ++i) {
    cin >> f[i] >> type[i];
    --type[i];
    G[f[i]].push_back(i);
    G[i].push_back(f[i]);
  }
  for (int x = 1; x <= (n); ++x)
    if (!vis[x]) {
      int u = x;
      vis[u] = 1;
      while (!vis[f[u]]) {
        u = f[u];
        vis[u] = 1;
      }
      incyc[u] = 1;
      while (!incyc[f[u]]) {
        u = f[u];
        incyc[u] = 1;
      }
      vector<int> tmpV = G[u];
      G[u].clear();
      int cntCyc = 0;
      for (int i = 0; i < tmpV.size(); ++i) {
        if (!incyc[tmpV[i]])
          G[u].push_back(tmpV[i]);
        else
          ++cntCyc;
      }
      anc = u;
      assert(cntCyc == 2);
      for (int i = 0; i < tmpV.size(); ++i)
        if (incyc[tmpV[i]]) {
          G[u].push_back(tmpV[i]);
          break;
        }
      dfsDP(u, 0);
      pair<int, int> tmp = dp[u][1];
      vec.clear();
      dfsPath(u, 0, 1);
      G[u].pop_back();
      for (int i = tmpV.size() - 1; i >= 0; --i)
        if (incyc[tmpV[i]]) {
          G[u].push_back(tmpV[i]);
          break;
        }
      dfsDP(u, 0);
      if (tmp < dp[u][1]) {
        ans += dp[u][1];
        vec.clear();
        dfsPath(u, 0, 1);
      } else
        ans += tmp;
      for (int i = 0; i < vec.size(); ++i) res.push_back(vec[i]);
    }
  cout << ans.first << ' ' << ans.second << endl;
  for (int i = 1; i <= (ans.first); ++i)
    cout << res[i - 1].first << ' ' << res[i - 1].second << endl;
  return 0;
}
