#include <iostream>
#include <vector>
#include <queue>
#include <unordered_set>
#include <unordered_map>
#include <climits>
#include <algorithm>

std::vector<std::vector<size_t>> get_adj_list(const std::unordered_map<long long int, std::vector<size_t>>& map_x,
                                           const std::unordered_map<long long int, std::vector<size_t>>& map_y,
                                           size_t nodes){
    std::vector<std::vector<size_t>> adjacency_list(nodes);

    for (auto it : map_x) {
        for (auto el : it.second) {
            adjacency_list[el].insert(adjacency_list[el].end(), it.second.begin(), it.second.end());
        }
    }
    for (auto it : map_y){
        for (auto el : it.second) {
            adjacency_list[el].insert(adjacency_list[el].end(), it.second.begin(), it.second.end());
        }
    }

    return adjacency_list;
}

std::unordered_set<size_t> bfs(const std::vector<std::vector<size_t>>& adjacency_list, int start)
{
    std::unordered_set<size_t> reached_nodes;
    std::vector<bool> reached(adjacency_list.size(), false);
    std::queue<size_t> q;
    q.push(start);
    while (!q.empty()){
        auto node = q.front();
        q.pop();
        if (!reached[node]){
            reached[node] = true;
            reached_nodes.insert(node);
            for (auto neighbor : adjacency_list[node])
                q.push(neighbor);
        }
    }

    return reached_nodes;
}

size_t get_num_of_connected_components(const std::vector<std::vector<size_t>>& adjacency_list)
{
    size_t ret = 0;
    std::unordered_set<size_t> reached_nodes;
    for (size_t i = 0; i < adjacency_list.size(); ++i)
    {
        if (reached_nodes.find(i) == reached_nodes.end()){
            reached_nodes.merge(bfs(adjacency_list, i));
            ret++;
        }
    }

    return ret;
}

size_t num_of_moves(const std::unordered_map<long long int, std::vector<size_t>>& map_x,
                 const std::unordered_map<long long int, std::vector<size_t>>& map_y,
                 size_t nodes)
{
    auto adj_list = get_adj_list(map_x, map_y, nodes);
    size_t num_of_connected_components = get_num_of_connected_components(adj_list);
    return num_of_connected_components - 1;
}

int main() {
    std::ios_base::sync_with_stdio(false);
    size_t nodes;
    long long int node_x, node_y;
    std::cin >> nodes;
    std::unordered_map<long long int, std::vector<size_t>> map_x;
    std::unordered_map<long long int, std::vector<size_t>> map_y;
    //std::vector<std::pair<int, int>> node_locations;
    //node_locations.reserve(nodes);

    for (size_t i = 0; i < nodes; ++i) {
        std::cin >> node_x >> node_y;
        auto [itx, insertedx]  = map_x.try_emplace(node_x, std::vector<size_t>());
        auto [ity, insertedy]  = map_y.try_emplace(node_y, std::vector<size_t>());
        itx->second.push_back(i);
        ity->second.push_back(i);
    }

    std::cout << num_of_moves(map_x, map_y, nodes);
    return 0;
}
