#include <bits/stdc++.h>
using namespace std;
template <class T>
using rque = priority_queue<T, vector<T>, greater<T>>;
const long long mod = 998244353;
long long gcd(long long a, long long b) {
  long long c = a % b;
  while (c != 0) {
    a = b;
    b = c;
    c = a % b;
  }
  return b;
}
long long extGCD(long long a, long long b, long long &x, long long &y) {
  if (b == 0) {
    x = 1;
    y = 0;
    return a;
  }
  long long d = extGCD(b, a % b, y, x);
  y -= a / b * x;
  return d;
}
struct UnionFind {
  vector<long long> data;
  UnionFind(int sz) { data.assign(sz, -1); }
  bool unite(int x, int y) {
    x = find(x), y = find(y);
    if (x == y) return (false);
    if (data[x] > data[y]) swap(x, y);
    data[x] += data[y];
    data[y] = x;
    return (true);
  }
  int find(int k) {
    if (data[k] < 0) return (k);
    return (data[k] = find(data[k]));
  }
  long long size(int k) { return (-data[find(k)]); }
};
long long M = 1000000007;
vector<long long> fac(2000011);
vector<long long> ifac(2000011);
long long mpow(long long x, long long n) {
  long long ans = 1;
  while (n != 0) {
    if (n & 1) ans = ans * x % M;
    x = x * x % M;
    n = n >> 1;
  }
  return ans;
}
long long mpow2(long long x, long long n, long long mod) {
  long long ans = 1;
  while (n != 0) {
    if (n & 1) ans = ans * x % mod;
    x = x * x % mod;
    n = n >> 1;
  }
  return ans;
}
void setcomb() {
  fac[0] = 1;
  ifac[0] = 1;
  for (long long i = 0; i < 2000010; i++) {
    fac[i + 1] = fac[i] * (i + 1) % M;
  }
  ifac[2000010] = mpow(fac[2000010], M - 2);
  for (long long i = 2000010; i > 0; i--) {
    ifac[i - 1] = ifac[i] * i % M;
  }
}
long long comb(long long a, long long b) {
  if (a == 0 && b == 0) return 1;
  if (a < b || a < 0) return 0;
  long long tmp = ifac[a - b] * ifac[b] % M;
  return tmp * fac[a] % M;
}
long long perm(long long a, long long b) {
  if (a == 0 && b == 0) return 1;
  if (a < b || a < 0) return 0;
  return fac[a] * ifac[a - b] % M;
}
long long modinv(long long a) {
  long long b = M, u = 1, v = 0;
  while (b) {
    long long t = a / b;
    a -= t * b;
    swap(a, b);
    u -= t * v;
    swap(u, v);
  }
  u %= M;
  if (u < 0) u += M;
  return u;
}
long long modinv2(long long a, long long mod) {
  long long b = mod, u = 1, v = 0;
  while (b) {
    long long t = a / b;
    a -= t * b;
    swap(a, b);
    u -= t * v;
    swap(u, v);
  }
  u %= mod;
  if (u < 0) u += mod;
  return u;
}
template <int mod>
struct ModInt {
  int x;
  ModInt() : x(0) {}
  ModInt(int64_t y) : x(y >= 0 ? y % mod : (mod - (-y) % mod) % mod) {}
  ModInt &operator+=(const ModInt &p) {
    if ((x += p.x) >= mod) x -= mod;
    return *this;
  }
  ModInt &operator-=(const ModInt &p) {
    if ((x += mod - p.x) >= mod) x -= mod;
    return *this;
  }
  ModInt &operator*=(const ModInt &p) {
    x = (int)(1LL * x * p.x % mod);
    return *this;
  }
  ModInt &operator/=(const ModInt &p) {
    *this *= p.inverse();
    return *this;
  }
  ModInt operator-() const { return ModInt(-x); }
  ModInt operator+(const ModInt &p) const { return ModInt(*this) += p; }
  ModInt operator-(const ModInt &p) const { return ModInt(*this) -= p; }
  ModInt operator*(const ModInt &p) const { return ModInt(*this) *= p; }
  ModInt operator/(const ModInt &p) const { return ModInt(*this) /= p; }
  bool operator==(const ModInt &p) const { return x == p.x; }
  bool operator!=(const ModInt &p) const { return x != p.x; }
  ModInt inverse() const {
    int a = x, b = mod, u = 1, v = 0, t;
    while (b > 0) {
      t = a / b;
      swap(a -= t * b, b);
      swap(u -= t * v, v);
    }
    return ModInt(u);
  }
  ModInt pow(int64_t n) const {
    ModInt ret(1), mul(x);
    while (n > 0) {
      if (n & 1) ret *= mul;
      mul *= mul;
      n >>= 1;
    }
    return ret;
  }
  friend ostream &operator<<(ostream &os, const ModInt &p) { return os << p.x; }
  friend istream &operator>>(istream &is, ModInt &a) {
    int64_t t;
    is >> t;
    a = ModInt<mod>(t);
    return (is);
  }
  static int get_mod() { return mod; }
};
using mint = ModInt<mod>;
vector<vector<mint>> mul(vector<vector<mint>> a, vector<vector<mint>> b) {
  int i, j, k;
  mint t;
  int n = a.size(), m = b[0].size(), l = a[0].size();
  vector<vector<mint>> c(n, vector<mint>(m));
  for (i = 0; i < n; i++) {
    for (j = 0; j < m; j++) {
      t = 0;
      for (k = 0; k < l; k++) t += a[i][k] * b[k][j];
      c[i][j] = t;
    }
  }
  return c;
}
vector<vector<mint>> mat_pow(vector<vector<mint>> x, long long n) {
  long long k = x.size();
  vector<vector<mint>> ans(k, vector<mint>(k, 0));
  for (int i = 0; i < k; i++) ans[i][i] = 1;
  while (n != 0) {
    if (n & 1) ans = mul(ans, x);
    x = mul(x, x);
    n = n >> 1;
  }
  return ans;
}
int main() {
  long long n;
  cin >> n;
  long long d[n], s[n];
  for (long long i = 0; i < (n); i++) cin >> d[i] >> s[i];
  queue<long long> que;
  vector<pair<long long, long long>> ans;
  for (long long i = 0; i < (n); i++)
    if (d[i] == 1) que.push(i);
  while (!que.empty()) {
    long long now = que.front();
    que.pop();
    if (d[now] == 1) {
      ans.push_back(make_pair(now, s[now]));
      d[now]--;
      d[s[now]]--;
      s[s[now]] ^= now;
      if (d[s[now]] == 1) que.push(s[now]);
    }
  }
  cout << ans.size() << endl;
  for (long long i = 0; i < (ans.size()); i++)
    cout << ans[i].first << " " << ans[i].second << endl;
}
