#include <bits/stdc++.h>
using namespace std;
const int BUF = 100005;
class Edge {
 public:
  int src, dst;
  Edge() {}
  Edge(int s, int d) : src(s), dst(d) {}
};
namespace std {
pair<int, int> operator+(pair<int, int> a, pair<int, int> b) {
  return make_pair(a.first + b.first, a.second + b.second);
}
pair<int, int> operator-(pair<int, int> a, pair<int, int> b) {
  return make_pair(a.first - b.first, a.second - b.second);
}
}  // namespace std
int nNode, nex[BUF];
bool isMale[BUF];
bool read() {
  if (!(cin >> nNode)) return false;
  for (int i = 0; i < nNode; i++) {
    int maleId;
    scanf("%d%d", &nex[i], &maleId);
    nex[i]--;
    isMale[i] = maleId == 1;
  }
  return true;
}
bool finished[BUF];
pair<int, int> rec(int curAvail, int cur, pair<int, int> dp[2][BUF],
                   vector<int> adj[BUF], int pre[2][BUF]) {
  finished[cur] = true;
  pair<int, int> &ret = dp[curAvail][cur];
  if (ret != make_pair(-1, -1)) return ret;
  ret = make_pair(0, 0);
  pair<int, int> sum = make_pair(0, 0);
  vector<Edge> allElect;
  for (int i = 0; i < adj[cur].size(); i++) {
    pair<int, int> t = rec(1, adj[cur][i], dp, adj, pre);
    sum = sum + t;
  }
  ret = sum;
  if (curAvail) {
    for (int i = 0; i < adj[cur].size(); i++) {
      pair<int, int> t = rec(1, adj[cur][i], dp, adj, pre),
                     s = rec(0, adj[cur][i], dp, adj, pre);
      if (ret <
          sum - t + s + make_pair(1, isMale[cur] != isMale[adj[cur][i]])) {
        ret = sum - t + s + make_pair(1, isMale[cur] != isMale[adj[cur][i]]);
        pre[curAvail][cur] = adj[cur][i];
      }
    }
  }
  return ret;
}
void getEdge(int curAvail, int cur, vector<int> adj[BUF], int pre[2][BUF],
             vector<Edge> &toPush) {
  for (int i = 0; i < adj[cur].size(); i++) {
    if (pre[curAvail][cur] != adj[cur][i])
      getEdge(1, adj[cur][i], adj, pre, toPush);
    else {
      toPush.push_back(Edge(cur, adj[cur][i]));
      getEdge(0, adj[cur][i], adj, pre, toPush);
    }
  }
}
void work() {
  memset(finished, 0, sizeof(finished));
  vector<int> adj[BUF];
  for (int i = 0; i < nNode; i++) adj[nex[i]].push_back(i);
  pair<int, int> num = make_pair(0, 0);
  vector<Edge> ans;
  static pair<int, int> dp[2][2][BUF];
  static int pre[2][2][BUF];
  memset(dp, -1, sizeof(dp));
  memset(pre, -1, sizeof(pre));
  for (int i = 0; i < nNode; i++) {
    if (finished[i]) continue;
    int toCalc = i;
    while (!finished[toCalc]) {
      finished[toCalc] = true;
      toCalc = nex[toCalc];
    }
    pair<int, int> maxV = make_pair(-1, -1);
    vector<Edge> toPush;
    for (int j = 0; j < 2; j++) {
      int src = nex[toCalc], dst = toCalc;
      adj[src].erase(find(adj[src].begin(), adj[src].end(), dst));
      pair<int, int> A = rec(1, dst, dp[j], adj, pre[j]);
      if (maxV < A) {
        maxV = A;
        toPush.clear();
        getEdge(1, dst, adj, pre[j], toPush);
      }
      adj[src].push_back(dst);
      toCalc = nex[toCalc];
    }
    num = num + maxV;
    ans.insert(ans.end(), toPush.begin(), toPush.end());
  }
  cout << num.first << ' ' << num.second << endl;
  for (int i = 0; i < ans.size(); i++)
    printf("%d %d\n", ans[i].src + 1, ans[i].dst + 1);
}
int main() {
  while (read()) work();
  return 0;
}
