#include <bits/stdc++.h>
using namespace std;
const int MAXN = 100000;
const int CHILD = 1;
const int PREV = 2;
int timestamp[MAXN + 10];
bool onCircle[MAXN + 10];
int f[MAXN + 10], s[MAXN + 10];
int n;
vector<int> ch[MAXN + 10];
void find(int x, int time) {
  vector<int> stk;
  while (!timestamp[x]) {
    timestamp[x] = time;
    stk.push_back(x);
    x = f[x];
  }
  if (timestamp[x] == time) {
    int j;
    do {
      j = stk.back();
      stk.pop_back();
      onCircle[j] = true;
      1;
    } while (j != x);
  }
}
vector<int> seq;
void lu(int st) {
  vector<int> q;
  q.push_back(st);
  while (!q.empty()) {
    int now = q.back();
    q.pop_back();
    seq.push_back(now);
    for (__typeof(ch[now].begin()) i = ch[now].begin(); i != ch[now].end(); ++i)
      q.push_back(*i);
  }
}
pair<int, int> operator+(pair<int, int> x, pair<int, int> y) {
  return make_pair(x.first + y.first, x.second + y.second);
}
pair<int, int> operator-(pair<int, int> x, pair<int, int> y) {
  return make_pair(x.first - y.first, x.second - y.second);
}
pair<int, int>& operator+=(pair<int, int>& a, pair<int, int> b) {
  a.first += b.first;
  a.second += b.second;
  return a;
}
pair<int, int> dpTree[MAXN + 10][2];
int treeChoose[MAXN + 10];
void DpTree() {
  for (__typeof(seq.begin()) x = seq.begin(); x != seq.end(); ++x) {
    dpTree[*x][true] = make_pair(0, 0);
    for (__typeof(ch[*x].begin()) i = ch[*x].begin(); i != ch[*x].end(); ++i)
      dpTree[*x][true] += dpTree[*i][false];
    dpTree[*x][false] = dpTree[*x][true];
    treeChoose[*x] = -1;
    for (__typeof(ch[*x].begin()) i = ch[*x].begin(); i != ch[*x].end(); ++i) {
      pair<int, int> cur = dpTree[*x][true] - dpTree[*i][false] +
                           dpTree[*i][true] + make_pair(1, s[*x] != s[*i]);
      if (cur > dpTree[*x][false]) {
        dpTree[*x][false] = cur;
        treeChoose[*x] = *i;
      }
    }
  }
}
void FangTree(int x, bool used, vector<pair<int, int> >& fang) {
  vector<pair<int, bool> > stk;
  stk.push_back(make_pair(x, used));
  while (!stk.empty()) {
    pair<int, bool> now = stk.back();
    stk.pop_back();
    if (now.second) {
      for (__typeof(ch[now.first].begin()) i = ch[now.first].begin();
           i != ch[now.first].end(); ++i)
        stk.push_back(make_pair(*i, false));
    } else {
      for (__typeof(ch[now.first].begin()) i = ch[now.first].begin();
           i != ch[now.first].end(); ++i)
        if (treeChoose[now.first] == *i)
          stk.push_back(make_pair(*i, true)),
              fang.push_back(make_pair(*i, now.first));
        else
          stk.push_back(make_pair(*i, false));
    }
  }
}
void FangCir(int* cirChoose, vector<int>& cir, vector<pair<int, int> >& fang) {
  bool flag = true;
  for (int i = (cir.size()) - 1; i >= 0; i--) {
    if (flag) {
      if (cirChoose[i] == CHILD)
        FangTree(cir[i], false, fang), flag = true;
      else {
        FangTree(cir[i], true, fang), flag = false;
        fang.push_back(make_pair(cir[i], cir[i - 1]));
      }
    } else {
      FangTree(cir[i], true, fang);
      flag = true;
    }
  }
}
pair<int, int> DpCircle(vector<int>& cir, vector<pair<int, int> >& fang) {
  static pair<int, int> dp[MAXN + 10][2];
  static int cirChoose[MAXN + 10];
  dp[0][false] = dpTree[cir[0]][true];
  dp[0][true] = dpTree[cir[0]][false];
  cirChoose[0] = CHILD;
  for (int j = (1); j <= (cir.size() - 1); j++) {
    dp[j][false] = dpTree[cir[j]][true] + dp[j - 1][true];
    pair<int, int> ifCh = dpTree[cir[j]][false] + dp[j - 1][true];
    pair<int, int> ifPr = dpTree[cir[j]][true] +
                          make_pair(1, s[cir[j]] != s[cir[j - 1]]) +
                          dp[j - 1][false];
    if (ifCh > ifPr) {
      cirChoose[j] = CHILD;
      dp[j][true] = ifCh;
    } else {
      cirChoose[j] = PREV;
      dp[j][true] = ifPr;
    }
  }
  cir.push_back(cir.front());
  cir.erase(cir.begin());
  static pair<int, int> dp2[MAXN + 10][2];
  static int cirChoose2[MAXN + 10];
  dp2[0][false] = dpTree[cir[0]][true];
  dp2[0][true] = dpTree[cir[0]][false];
  cirChoose2[0] = CHILD;
  for (int j = (1); j <= (cir.size() - 1); j++) {
    dp2[j][false] = dpTree[cir[j]][true] + dp2[j - 1][true];
    pair<int, int> ifCh = dpTree[cir[j]][false] + dp2[j - 1][true];
    pair<int, int> ifPr = dpTree[cir[j]][true] +
                          make_pair(1, s[cir[j]] != s[cir[j - 1]]) +
                          dp2[j - 1][false];
    if (ifCh > ifPr) {
      cirChoose2[j] = CHILD;
      dp2[j][true] = ifCh;
    } else {
      cirChoose2[j] = PREV;
      dp2[j][true] = ifPr;
    }
  }
  if (dp[cir.size() - 1][true] > dp2[cir.size() - 1][true]) {
    cir.insert(cir.begin(), cir.back());
    cir.pop_back();
    FangCir(cirChoose, cir, fang);
    return dp[cir.size() - 1][true];
  } else {
    FangCir(cirChoose2, cir, fang);
    return dp2[cir.size() - 1][true];
  }
}
int main() {
  scanf("%d", &n);
  for (int i = 0; i < (n); i++) scanf("%d%d", &f[i], &s[i]), f[i]--;
  for (int i = 0; i < (n); i++) find(i, i + 1);
  for (int i = 0; i < (n); i++)
    if (!onCircle[i]) ch[f[i]].push_back(i);
  for (int i = 0; i < (n); i++)
    if (onCircle[i]) lu(i);
  reverse(seq.begin(), seq.end());
  DpTree();
  memset(timestamp, false, sizeof(timestamp));
  pair<int, int> ans = make_pair(0, 0);
  vector<pair<int, int> > fang;
  for (int i = 0; i < (n); i++)
    if (onCircle[i] && !timestamp[i]) {
      vector<int> cir;
      for (int x = i; !timestamp[x]; x = f[x])
        cir.push_back(x), timestamp[x] = true;
      ans += DpCircle(cir, fang);
    }
  cout << ans.first << ' ' << ans.second << endl;
  for (__typeof(fang.begin()) i = fang.begin(); i != fang.end(); ++i)
    printf("%d %d\n", i->first + 1, i->second + 1);
  return 0;
}
