#include <bits/stdc++.h>
#pragma GCC optimize("Ofast")
#pragma GCC target("avx,avx2,fma")
#pragma GCC optimization("unroll-loops")
using namespace std;
array<long long, 2> parent[1000][1000];
long long sze[1000][1000];
array<long long, 2> p(array<long long, 2> x) {
  if (x == parent[x[0]][x[1]]) {
    return x;
  } else {
    return parent[x[0]][x[1]] = p(parent[x[0]][x[1]]);
  }
}
void unite(array<long long, 2> x, array<long long, 2> y) {
  array<long long, 2> a = p(x);
  array<long long, 2> b = p(y);
  if (a != b) {
    if (sze[a[0]][a[1]] < sze[b[0]][b[1]]) {
      swap(a, b);
    }
    parent[b[0]][b[1]] = a;
    sze[a[0]][a[1]] += sze[b[0]][b[1]];
  }
}
int32_t main() {
  ios_base::sync_with_stdio(false);
  cin.tie(NULL);
  cout.tie(NULL);
  ;
  long long n;
  cin >> n;
  unordered_map<long long, vector<array<long long, 2>>> m1;
  unordered_map<long long, vector<array<long long, 2>>> m2;
  vector<array<long long, 2>> a(n);
  for (long long i = 0; i < n; ++i) {
    long long x, y;
    cin >> x >> y;
    x--;
    y--;
    a[i] = {x, y};
    m1[x].push_back({x, y});
    m2[y].push_back({x, y});
  }
  for (long long i = 0; i < 1000; ++i) {
    for (long long j = 0; j < 1000; ++j) {
      parent[i][j] = {i, j};
      sze[i][j] = 1;
    }
  }
  for (auto i : a) {
    for (auto j : m1[i[0]]) {
      if (j == i) {
        continue;
      }
      unite(i, j);
    }
    for (auto j : m2[i[1]]) {
      if (j == i) {
        continue;
      }
      unite(i, j);
    }
  }
  long long ans = 0;
  for (auto i : a) {
    if (i == parent[i[0]][i[1]]) {
      ans++;
    }
  }
  cout << ans - 1 << '\n';
  return 0;
}
