#include <bits/stdc++.h>
using namespace std;
template <class T1, class T2>
ostream& operator<<(ostream& os, const pair<T1, T2>& p) {
  os << "{" << p.first << ", " << p.second << "}";
  return os;
}
template <class T>
ostream& operator<<(ostream& os, const vector<T>& p) {
  os << "[";
  int i = 0;
  for (typename vector<T>::const_iterator it = p.begin(); it != p.end(); ++it) {
    os << (i == 0 ? "" : ", ") << *it;
    i++;
  }
  os << "]";
  return os;
}
template <class T>
ostream& operator<<(ostream& os, const set<T>& p) {
  os << "[";
  int i = 0;
  for (typename set<T>::const_iterator it = p.begin(); it != p.end(); ++it) {
    os << (i == 0 ? "" : ", ") << *it;
    i++;
  }
  os << "]";
  return os;
}
template <class K, class V>
ostream& operator<<(ostream& os, const map<K, V>& p) {
  os << "[";
  int i = 0;
  for (typename map<K, V>::const_iterator it = p.begin(); it != p.end(); ++it) {
    os << (i == 0 ? "" : ", ") << *it;
    i++;
  }
  os << "]";
  return os;
}
template <class T>
string toString(const T& o) {
  stringstream ss;
  ss << o;
  string ret;
  getline(ss, ret);
  return ret;
}
template <class T>
vector<T> subv(const vector<T>& v, int from, int to) {
  return vector<T>(v.begin() + min(max(0, from), (int)v.size()),
                   v.begin() + min(max(0, to), (int)v.size()));
}
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> operator*(const int& a, const pair<int, int>& b) {
  return make_pair(a * b.first, a * b.second);
}
vector<int> sex, parent, used[2], path, bestw[2];
vector<int> was;
vector<int> points;
vector<vector<int> > adj;
vector<pair<int, int> > w[2], o[2];
int k, mark, n;
void dfs(int v, int color) {
  if (was[v] == color) {
    points.push_back(v);
    return;
  }
  if (was[v]) return;
  was[v] = color;
  for (int i = 0; i < adj[v].size(); ++i) dfs(adj[v][i], color);
}
void go(int v) {
  if (used[k][v]) return;
  used[k][v] = 1;
  w[k][v] = o[k][v] = make_pair(0, 0);
  for (int i = 0; i < adj[v].size(); ++i) {
    int to = adj[v][i];
    go(to);
    if (mark != to) o[k][v] = o[k][v] + max(w[k][to], o[k][to]);
  }
  for (int i = 0; i < adj[v].size(); ++i) {
    int to = adj[v][i];
    if (to == mark) continue;
    pair<int, int> val = o[k][v] + (-1) * max(w[k][to], o[k][to]) + o[k][to] +
                         make_pair(1, sex[v] != sex[to]);
    if (w[k][v] < val) {
      bestw[k][v] = to;
      w[k][v] = val;
    }
  }
}
void make_path(int v, bool with) {
  int to = -1;
  if (with) {
    to = bestw[k][v];
    path[to] = 1;
  }
  for (int i = 0; i < adj[v].size(); ++i) {
    int to2 = adj[v][i];
    if (to2 != mark) make_path(to2, (to2 != to) && (w[k][to2] > o[k][to2]));
  }
}
int main() {
  cin >> n;
  adj.resize(n);
  sex.resize(n);
  path.resize(n, 0);
  parent.resize(n);
  was.resize(n, 0);
  for (int i = 0; i < 2; ++i) {
    bestw[i].resize(n, -1);
    w[i].resize(n);
    o[i].resize(n);
    used[i].resize(n, 0);
  }
  for (int i = 0; i < n; ++i) {
    int f, s;
    cin >> f >> s;
    f--, s--;
    parent[i] = f;
    sex[i] = s;
    adj[f].push_back(i);
  }
  for (int i = 0; i < n; ++i)
    if (!was[i]) dfs(i, i + 1);
  for (int i = 0; i < points.size(); ++i) {
    int v1 = points[i];
    int v2 = parent[v1];
    k = 0;
    mark = v1;
    go(v1);
    k = 1;
    mark = v2;
    go(v2);
    int v;
    if (max(o[0][v1], w[0][v1]) > max(o[1][v2], w[1][v2])) {
      k = 0;
      v = v1;
      mark = v1;
    } else {
      k = 1;
      v = v2;
      mark = v2;
    }
    make_path(v, w[k][v] > o[k][v]);
  }
  int all = 0, diff = 0;
  for (int i = 0; i < n; ++i)
    if (path[i]) {
      all++;
      diff += (sex[i] != sex[parent[i]]);
    }
  cout << all << " " << diff << endl;
  for (int i = 0; i < n; ++i)
    if (path[i]) cout << i + 1 << " " << parent[i] + 1 << endl;
  return 0;
}
