#include using namespace std; #define ll long long #define vll vector #define vvll vector #define vpll vector> #define pll array #define rep(i, n) for(ll i = 0; i < (ll)n; i++) #define rep1(i, n) for(ll i = 1; i <= (ll)n; i++) #define fi first #define se second #define debug false struct DSU { vll parent, size; DSU(ll n){ parent = vll(n); size = vll(n); rep(i, n) { make_set(i); } } void make_set(ll v){ parent[v] = v; size[v] = 1; } void union_set(ll a, ll b){ a = find_set(a); b = find_set(b); if(a != b){ if (size[a] < size[b]) swap(a, b); parent[b] = a; size[a] += size[b]; } } ll find_set(ll a){ if(a == parent[a]) return a; return find_set(parent[a]); } }; int main() { // freopen("./in.txt", "r", stdin); // freopen("./out.txt", "w", stdout); // cout << "COMMENT THIS OUT" << endl; cin.tie(nullptr); cout.tie(nullptr); ios_base::sync_with_stdio(false); ll N; cin >> N; vpll xy(N); rep(i, N){ ll x, y; cin >> x >> y; xy[i][0] = x; xy[i][1] = y; xy[i][2] = i; } sort(xy.begin(), xy.end(), [](const pll& a, const pll& b){ return a[0] < b[0]; }); DSU uf(N); rep1(i, N-1){ const pll& a = xy[i-1]; const pll& b = xy[i]; if(a[0] == b[0]){ uf.union_set(a[2], b[2]); } } sort(xy.begin(), xy.end(), [](const pll& a, const pll& b){ return a[1] < b[1]; }); rep1(i, N-1){ const pll& a = xy[i-1]; const pll& b = xy[i]; if(a[1] == b[1]){ uf.union_set(a[2], b[2]); } } unordered_map x; rep(i, N){ ll s = uf.find_set(i); if(!x.count(s)){ x[s] = 1; } } ll components = 0; rep(i, N){ if(x.count(i)) components++; } cout << components - 1 << endl; return 0; }