#include <bits/stdc++.h>
void Get(int &T) {
  char C;
  bool F = 0;
  for (; C = getchar(), C < '0' || C > '9';)
    if (C == '-') F = 1;
  for (T = C - '0'; C = getchar(), C >= '0' && C <= '9'; T = T * 10 + C - '0')
    ;
  F && (T = -T);
}
int N;
int T[100005];
struct E {
  int V, Next;
} Edge[200005];
int EdgeTop;
int Head[100005];
void Add(int U, int V) {
  Edge[++EdgeTop] = (E){V, Head[U]};
  Head[U] = EdgeTop;
}
int V[100005];
void Init() {
  Get(N);
  for (int i = 1; i <= N; i++) {
    Get(V[i]);
    Get(T[i]);
    if (i != V[i] && V[V[i]] != i) {
      Add(i, V[i]);
      Add(V[i], i);
    }
  }
}
int Fa[100005];
long long F[100005][5];
long long BestF[100005];
int BestFID[100005];
int FromF[100005][5];
long long G[100005][5];
long long BestG[100005];
int BestGID[100005];
long long H[100005][5];
long long BestH[100005];
int BestHID[100005];
void Rec(int Y, int X) {
  for (int i = Y;; i = Fa[i]) {
    G[i][0] = H[i][0] = F[i][0];
    G[i][1] = H[i][1] = F[i][1];
    BestG[i] = BestH[i] = BestF[i];
    BestGID[i] = BestHID[i] = BestFID[i];
    if (i == X) break;
  }
  G[Y][1] = G[Y][0];
  G[Y][0] = 0xc0c0c0c0c0c0c0c0ll;
  for (int i = Y;; i = Fa[i]) {
    if (i == X) break;
    G[Fa[i]][0] += G[i][1];
    if (BestG[Fa[i]] < G[i][0] + (1000000ll + (T[Fa[i]] != T[i])) - G[i][1]) {
      BestG[Fa[i]] = G[i][0] + (1000000ll + (T[Fa[i]] != T[i])) - G[i][1];
      BestGID[Fa[i]] = i;
    }
    G[Fa[i]][1] = G[Fa[i]][0] + BestG[Fa[i]];
    H[Fa[i]][0] += H[i][1];
    if (BestH[Fa[i]] < H[i][0] + (1000000ll + (T[Fa[i]] != T[i])) - H[i][1]) {
      BestH[Fa[i]] = H[i][0] + (1000000ll + (T[Fa[i]] != T[i])) - H[i][1];
      BestHID[Fa[i]] = i;
    }
    H[Fa[i]][1] = H[Fa[i]][0] + BestH[Fa[i]];
  }
  G[X][1] = G[X][0] + (1000000ll + (T[X] != T[Y]));
  BestGID[X] = Y;
}
int Low[100005];
int DFN[100005];
int Time;
void DFS(int X) {
  DFN[X] = Low[X] = ++Time;
  BestF[X] = 0;
  for (int i = Head[X]; i; i = Edge[i].Next) {
    if (Fa[X] != Edge[i].V) {
      if (DFN[Edge[i].V] == 0) {
        Fa[Edge[i].V] = X;
        DFS(Edge[i].V);
        if (Low[X] > Low[Edge[i].V]) Low[X] = Low[Edge[i].V];
        if (Low[Edge[i].V] > DFN[X]) {
          F[X][0] += F[Edge[i].V][1];
          if (BestF[X] < F[Edge[i].V][0] +
                             (1000000ll + (T[X] != T[Edge[i].V])) -
                             F[Edge[i].V][1]) {
            BestF[X] = F[Edge[i].V][0] + (1000000ll + (T[X] != T[Edge[i].V])) -
                       F[Edge[i].V][1];
            BestFID[X] = Edge[i].V;
          }
        }
      } else {
        if (Low[X] > DFN[Edge[i].V]) Low[X] = DFN[Edge[i].V];
      }
    }
  }
  F[X][1] = F[X][0] + BestF[X];
  for (int i = Head[X]; i; i = Edge[i].Next)
    if (DFN[Edge[i].V] > DFN[X] && Fa[Edge[i].V] != X) {
      Rec(Edge[i].V, X);
      if (F[X][0] < G[X][0]) {
        F[X][0] = G[X][0];
        FromF[X][0] = 1;
      }
      if (F[X][0] < H[X][0]) {
        F[X][0] = H[X][0];
        FromF[X][0] = 2;
      }
      if (F[X][1] < G[X][1]) {
        F[X][1] = G[X][1];
        FromF[X][1] = 1;
      }
      if (F[X][1] < H[X][1]) {
        F[X][1] = H[X][1];
        FromF[X][1] = 2;
      }
    }
}
int Ans2[5][100005];
int AnsTop2;
bool End[100005];
void Solu(int Type, int i, int j) {
  int FGH = FromF[i][j];
  if (Type == 0) Type = FGH;
  if (j == 1) {
    if (Type == 0 && Fa[BestFID[i]] != i && BestFID[i] != 0) {
      Ans2[1][++AnsTop2] = i;
      Ans2[2][AnsTop2] = BestFID[i];
      End[BestFID[i]] = 1;
      j = 0;
    } else if (Type == 1 && Fa[BestGID[i]] != i && BestGID[i] != 0) {
      Ans2[1][++AnsTop2] = i;
      Ans2[2][AnsTop2] = BestGID[i];
      End[BestGID[i]] = 1;
      j = 0;
    } else if (Type == 2 && Fa[BestHID[i]] != i && BestHID[i] != 0) {
      Ans2[1][++AnsTop2] = i;
      Ans2[2][AnsTop2] = BestHID[i];
      End[BestHID[i]] = 1;
      j = 0;
    }
  }
  if (End[i] == 1) j = 0;
  for (int k = Head[i]; k; k = Edge[k].Next) {
    int j0 = j;
    if (j == 0)
      j0 = 1;
    else {
      if (Type == 0 && BestFID[i] == Edge[k].V) {
        j0 = 0;
        Ans2[1][++AnsTop2] = i;
        Ans2[2][AnsTop2] = Edge[k].V;
      }
      if (Type == 1 && BestGID[i] == Edge[k].V) {
        j0 = 0;
        Ans2[1][++AnsTop2] = i;
        Ans2[2][AnsTop2] = Edge[k].V;
      }
      if (Type == 2 && BestHID[i] == Edge[k].V) {
        j0 = 0;
        Ans2[1][++AnsTop2] = i;
        Ans2[2][AnsTop2] = Edge[k].V;
      }
    }
    if (Fa[Edge[k].V] == i) {
      if (Low[i] == Low[Edge[k].V])
        Solu(Type, Edge[k].V, j0);
      else
        Solu(0, Edge[k].V, j0);
    }
  }
}
long long Ans;
void Work() {
  for (int i = 1; i <= N; i++) {
    if (DFN[i] == 0) {
      DFS(i);
      if ((F[i][0] > F[i][1])) {
        Ans += F[i][0];
        Solu(0, i, 0);
      } else {
        Ans += F[i][1];
        Solu(0, i, 1);
      }
    }
  }
}
void Output() {
  puts("");
  printf("%I64d %I64d\n", Ans / 1000000ll, Ans % 1000000ll);
  for (int i = 1; i <= AnsTop2; i++) printf("%d %d\n", Ans2[1][i], Ans2[2][i]);
}
int main() {
  Init();
  Work();
  Output();
  return 0;
}
