#include <bits/stdc++.h>
#pragma comment(linker, "/STACK:102400000,102400000")
template <class T>
inline void gmax(T &a, T b) {
  if (b > a) a = b;
}
template <class T>
inline void gmin(T &a, T b) {
  if (b < a) a = b;
}
using namespace std;
const int N = 1e5 + 100;
const double PI = acos(-1.0);
void fre() {
  freopen("/Users/luras/Desktop/in.txt", "r", stdin);
  freopen("/Users/luras/Desktop/out.txt", "w", stdout);
}
const int INF = 16843009;
int casenum, casei;
struct A {
  int num, sum, x, y;
} a[N], t, tt, c[N];
queue<A> q;
set<int> sot[N];
int n, id;
int main() {
  scanf("%d", &n);
  id = 0;
  for (int i = 0; i < n; i++) {
    scanf("%d%d", &a[i].num, &a[i].sum);
    a[i].x = i;
    if (a[i].num == 1 && sot[a[i].x].find(a[i].sum) == sot[a[i].x].end() &&
        sot[a[i].sum].find(a[i].x) == sot[a[i].sum].end()) {
      q.push(a[i]);
      sot[a[i].x].insert(a[i].sum);
      id++;
    }
  }
  while (!q.empty()) {
    t = q.front();
    q.pop();
    a[t.sum].num--;
    a[t.sum].sum ^= t.x;
    if (sot[t.sum].find(t.x) == sot[t.sum].end() &&
        sot[t.x].find(t.sum) == sot[t.x].end()) {
      sot[t.sum].insert(t.x);
      id++;
    }
    if (a[t.sum].num == 1) {
      q.push(a[t.sum]);
    }
  }
  set<int>::iterator it;
  printf("%d\n", id);
  for (int i = 0; i < n; i++) {
    for (it = sot[i].begin(); it != sot[i].end(); it++) {
      printf("%d %d\n", i, *it);
    }
  }
  return 0;
}
