#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <string>
#include <vector>
#include <list>
#include <set>
#include <map>
#include <stack>
#include <queue>
#define llong long long
#define INF (__INT32_MAX__ / 2)
#define EPS 10e-8
#define MAX_N 100000

using namespace std;
typedef pair<llong, llong> ipair;
llong modulo(llong left, llong right) { return (left % right + right) % right; }

int N, M;
vector<ipair> x_towns, y_towns;
priority_queue<tuple<int, int, int>> edge_cost;
vector<tuple<int, int, llong>> edges;

class DisjointSet {
    private:
    class Node {
        public: 
        int parent = -1;
        int rank = 0;
        int degree = 1;
    };
    
    Node *nodes;
    
    void make_set(int x) {
        ++count;
        nodes[x].parent = x;
        nodes[x].rank = 0;
        nodes[x].degree = 1;
    }

    public:
    int count = 0;

    DisjointSet(){}
    DisjointSet(int length) {
        nodes = (Node *)malloc(sizeof(Node) * length);
        for(int i = 0; i < length; ++i)
            make_set(i);
    }

    ~DisjointSet() {
        free(nodes);
    }

    int find_set(int x) {
        if(nodes[x].parent == x)
            return x;

        return nodes[x].parent = find_set(nodes[x].parent);
    }

    int get_degree(int x) {
        return nodes[find_set(x)].degree;
    }

    void unite(int x, int y) {
        int set_x = find_set(x);
        int set_y = find_set(y);
        if(set_x == set_y) return;
        --count;

        if(nodes[x].rank < nodes[y].rank) {
            nodes[set_x].parent = set_y;
            nodes[y].degree += nodes[x].degree;
        } else if(nodes[x].rank > nodes[y].rank) {
            nodes[set_y].parent = set_x;
            nodes[x].degree += nodes[y].degree;
        } else {
            nodes[set_y].parent = set_x;
            nodes[x].rank++;
            nodes[x].degree += nodes[y].degree;
        }
    }

    bool is_same(int x, int y) {
        int set_x = find_set(x);
        int set_y = find_set(y);
        return set_x == set_y;
    }
};

int kruskal() {
    llong res = 0;

    auto *dset = new DisjointSet(N);
    while(!edge_cost.empty()) {
        int cost = -get<0>(edge_cost.top());
        int st = get<1>(edge_cost.top());
        int ed = get<2>(edge_cost.top()); edge_cost.pop();

        if(!dset->is_same(st, ed)) {
            res += cost;
            dset->unite(st, ed);
        }

    }

    return res;
}

int main(int argc, char **argv) {
    cin >> N;
    for(int i = 0; i < N; ++i) {
        int x, y;
        cin >> x >> y;
        x_towns.push_back(make_pair(x - 1, i));
        y_towns.push_back(make_pair(y - 1, i));
    }
    sort(x_towns.begin(), x_towns.end());
    sort(y_towns.begin(), y_towns.end());
    for(int i = 0; i < x_towns.size() - 1; ++i)
        edge_cost.push(make_tuple(
            -(x_towns[i + 1].first - x_towns[i].first), 
            x_towns[i].second, 
            x_towns[i + 1].second));

    for(int i = 0; i < y_towns.size() - 1; ++i)
        edge_cost.push(make_tuple(
            -(y_towns[i + 1].first - y_towns[i].first), 
            y_towns[i].second, 
            y_towns[i + 1].second));

    cout << kruskal() << endl; 
}

Measured memory_bytes: 9444