#include using namespace std; using ll = long long; struct coord { ll x = 0, y = 0; vector neighbors; coord() = default; coord(ll x, ll y) : x(x), y(y), neighbors() {} }; int main() { std::istream::sync_with_stdio(false); ll n; cin >> n; vector coords(n); for (ll i = 0; i < n; ++i) { ll x, y; cin >> x >> y; coords[i] = coord(x, y); } unordered_map> rows; unordered_map> columns; for (ll i = 0; i < n; ++i) { coord & currCoord = coords[i]; if (rows.count(currCoord.y) == 0) rows[currCoord.y] = {i}; else { ll lastCoordIndex = rows[currCoord.y][rows[currCoord.y].size() - 1]; coord & lastCoord = coords[lastCoordIndex]; lastCoord.neighbors.push_back(i); currCoord.neighbors.push_back(lastCoordIndex); } } for (ll i = 0; i < n; ++i) { coord & currCoord = coords[i]; if (columns.count(currCoord.x) == 0) columns[currCoord.x] = {i}; else { ll lastCoordIndex = columns[currCoord.x][columns[currCoord.x].size() - 1]; coord & lastCoord = coords[lastCoordIndex]; lastCoord.neighbors.push_back(i); currCoord.neighbors.push_back(lastCoordIndex); } } vector visited(n, false); ll result = 0; for (ll i = 0; i < n; ++i) { if (visited[i]) continue; ++result; queue q; q.push(i); visited[i] = true; while (!q.empty()) { ll currIndex = q.front(); q.pop(); const coord & currCoord = coords[currIndex]; for (ll x : currCoord.neighbors) { if (visited[x]) continue; q.push(x); visited[x] = true; } } } cout << result - 1 << '\n'; return 0; }