#include <bits/stdc++.h>
#pragma comment(linker, "/stack:64000000")
using namespace std;
template <typename first>
inline first abs(const first& a) {
  return a < 0 ? -a : a;
}
template <typename first>
inline first sqr(const first& a) {
  return a * a;
}
const long double PI = 3.1415926535897932384626433832795;
const long double EPS = 1e-9;
const int INF = 1000 * 1000 * 1000;
const int N = 100 * 1000 + 13;
int n;
int type[N];
vector<int> g[N], tg[N];
int ansVal = 0, ansBG = 0;
vector<pair<int, int> > ans;
vector<int> cyc;
int used[N], U = 1;
int calced[N];
int V, PV;
pair<int, int> d[N][2][2];
int bestTo[N][2][2];
inline 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));
}
inline 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> solve(int v, int may, int takeLast) {
  pair<int, int>& res = d[v][may][takeLast];
  if (res.first != -1) return res;
  pair<int, int> sumNext = make_pair((0), (0));
  for (int i = 0; i < int(int((tg[v]).size())); i++) {
    int to = tg[v][i];
    if (to != V) sumNext = sumNext + solve(to, 1, takeLast);
  }
  res = sumNext;
  if (may == 0 || (v == V && takeLast)) return res;
  if (v == PV && takeLast) {
    pair<int, int> nw = sumNext + make_pair((1), (type[v] != type[V]));
    if (nw > res) res = nw, bestTo[v][may][takeLast] = V;
    return res;
  }
  for (int i = 0; i < int(int((tg[v]).size())); i++) {
    int to = tg[v][i];
    if ((v == PV && to == V) || (to == PV && takeLast)) continue;
    pair<int, int> nw = sumNext - solve(to, 1, takeLast) +
                        solve(to, 0, takeLast) +
                        make_pair((1), (type[v] != type[to]));
    if (nw > res) res = nw, bestTo[v][may][takeLast] = to;
  }
  return res;
}
void restore(int v, int may, int takeLast) {
  int& To = bestTo[v][may][takeLast];
  if (To != -1) {
    ans.push_back(make_pair((v), (To)));
    if (To != V) restore(To, 0, takeLast);
  }
  for (int i = 0; i < int(int((tg[v]).size())); i++) {
    int to = tg[v][i];
    if (to != To && to != V) restore(to, 1, takeLast);
  }
}
void dfs(int v) {
  calced[v] = true;
  for (int i = 0; i < int(int((tg[v]).size())); i++) {
    int to = tg[v][i];
    if (!calced[to]) dfs(to);
  }
}
void solveComp(int v) {
  cyc.clear();
  while (used[v] != U) {
    cyc.push_back(v);
    used[v] = U;
    v = g[v][0];
  }
  cyc.push_back(v);
  reverse((cyc).begin(), (cyc).end());
  while (cyc.back() != cyc[0]) cyc.pop_back();
  reverse((cyc).begin(), (cyc).end());
  dfs(cyc[0]);
  V = cyc[0];
  PV = cyc[1];
  pair<int, int> ans1 = solve(cyc[0], 0, 1);
  pair<int, int> ans2 = solve(cyc[0], 1, 0);
  if (ans1 > ans2) {
    ansVal += ans1.first, ansBG += ans1.second;
    restore(cyc[0], 0, 1);
  } else {
    ansVal += ans2.first, ansBG += ans2.second;
    restore(cyc[0], 1, 0);
  }
}
int main() {
  memset(d, -1, sizeof(d));
  memset(bestTo, -1, sizeof(bestTo));
  cin >> n;
  for (int i = 0; i < int(n); i++) {
    int to;
    scanf("%d%d", &to, &type[i]);
    --to, --type[i];
    g[i].push_back(to);
    tg[to].push_back(i);
  }
  for (int i = 0; i < int(n); i++)
    if (!calced[i]) solveComp(i);
  printf("%d %d\n", ansVal, ansBG);
  assert(int((ans).size()) == ansVal);
  int cntBG = 0;
  for (int i = 0; i < int(int((ans).size())); i++) {
    cntBG += (type[ans[i].first] != type[ans[i].second]);
    printf("%d %d\n", ans[i].first + 1, ans[i].second + 1);
  }
  assert(cntBG == ansBG);
  return 0;
}
