#include <bits/stdc++.h>
using 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);
}
int n;
int f[100010], s[100010];
vector<int> ke[100010];
int cur, ROOT;
pair<int, int> F[2][100010][2];
bool dt[2][100010][2];
pair<int, int> calc(int i, bool b) {
  if (dt[cur][i][b]) return F[cur][i][b];
  dt[cur][i][b] = true;
  pair<int, int> res = make_pair(0, 0);
  if (!b) {
    for (int k = 0; k < (ke[i].size()); ++k) {
      int j = ke[i][k];
      if (j != ROOT && f[j] == i) {
        res = res + max(calc(j, 0), calc(j, 1));
      }
    }
  } else {
    pair<int, int> total = make_pair(0, 0);
    for (int k = 0; k < (ke[i].size()); ++k) {
      int j = ke[i][k];
      if (j != ROOT && f[j] == i) {
        total = total + max(calc(j, 0), calc(j, 1));
      }
    }
    res = total;
    for (int k = 0; k < (ke[i].size()); ++k) {
      int j = ke[i][k];
      if (j != ROOT && f[j] == i) {
        res = max(res, total - max(calc(j, 0), calc(j, 1)) + calc(j, 0) +
                           make_pair(1, s[j] != s[i] ? 1 : 0));
      }
    }
  }
  return F[cur][i][b] = res;
}
void truy(int i, int b, vector<pair<int, int> > &v) {
  pair<int, int> res = calc(i, b);
  if (!b) {
    for (int k = 0; k < (ke[i].size()); ++k) {
      int j = ke[i][k];
      if (j != ROOT && f[j] == i) {
        pair<int, int> p0 = calc(j, 0);
        pair<int, int> p1 = calc(j, 1);
        if (p0 > p1)
          truy(j, 0, v);
        else
          truy(j, 1, v);
      }
    }
  } else {
    pair<int, int> total = make_pair(0, 0);
    for (int k = 0; k < (ke[i].size()); ++k) {
      int j = ke[i][k];
      if (j != ROOT && f[j] == i) {
        total = total + max(calc(j, 0), calc(j, 1));
      }
    }
    if (total == res) {
      for (int k = 0; k < (ke[i].size()); ++k) {
        int j = ke[i][k];
        if (j != ROOT && f[j] == i) {
          pair<int, int> p0 = calc(j, 0);
          pair<int, int> p1 = calc(j, 1);
          if (p0 > p1)
            truy(j, 0, v);
          else
            truy(j, 1, v);
        }
      }
    } else {
      for (int k = 0; k < (ke[i].size()); ++k) {
        int j = ke[i][k];
        if (j != ROOT && f[j] == i) {
          pair<int, int> z = total - max(calc(j, 0), calc(j, 1)) + calc(j, 0) +
                             make_pair(1, s[j] != s[i] ? 1 : 0);
          if (z == res) {
            v.push_back(make_pair(i, j));
            for (int t = 0; t < (ke[i].size()); ++t) {
              int j = ke[i][t];
              if (j != ROOT && f[j] == i) {
                if (t == k)
                  truy(j, 0, v);
                else {
                  pair<int, int> p0 = calc(j, 0);
                  pair<int, int> p1 = calc(j, 1);
                  if (p0 > p1)
                    truy(j, 0, v);
                  else
                    truy(j, 1, v);
                }
              }
            }
            break;
          }
        }
      }
    }
  }
}
void solve(int root, pair<int, int> &p, vector<pair<int, int> > &v) {
  ROOT = root;
  pair<int, int> p0 = calc(root, 0);
  pair<int, int> p1 = calc(root, 1);
  if (p0 > p1) {
    p = p0;
    truy(root, 0, v);
  } else {
    p = p1;
    truy(root, 1, v);
  }
}
bool mark[100010];
bool vs[100010];
void dfs(int i) {
  vs[i] = true;
  for (int k = 0; k < (ke[i].size()); ++k) {
    int j = ke[i][k];
    if (!vs[j]) dfs(j);
  }
}
void process(int si, pair<int, int> &p, vector<pair<int, int> > &v) {
  dfs(si);
  int tr = -1;
  while (!mark[si]) {
    mark[si] = true;
    tr = si;
    si = f[si];
  }
  pair<int, int> p1, p2;
  vector<pair<int, int> > v1, v2;
  cur = 1 - cur;
  solve(tr, p1, v1);
  p = p1;
  v = v1;
  cur = 1 - cur;
  solve(si, p2, v2);
  if (p1 < p2) {
    p = p2, v = v2;
  } else {
    p = p1, v = v1;
  }
}
int main() {
  scanf("%d", &n);
  for (int i = (1); i <= (n); ++i) scanf("%d%d", f + i, s + i);
  memset(F, -1, sizeof(F));
  for (int i = (1); i <= (n); ++i) {
    if (f[f[i]] != i) ke[i].push_back(f[i]), ke[f[i]].push_back(i);
  }
  for (int i = (1); i <= (n); ++i) {
    if (f[f[i]] == i) ke[i].push_back(f[i]);
  }
  pair<int, int> res = make_pair(0, 0);
  vector<pair<int, int> > vr;
  for (int i = (1); i <= (n); ++i)
    if (!vs[i]) {
      pair<int, int> p;
      vector<pair<int, int> > v;
      process(i, p, v);
      res = res + p;
      for (int j = 0; j < (v.size()); ++j) vr.push_back(v[j]);
    }
  printf("%d %d\n", res.first, res.second);
  for (int i = 0; i < (vr.size()); ++i) {
    printf("%d %d\n", vr[i].first, vr[i].second);
  }
  return 0;
}
