#include <bits/stdc++.h>

#define LL long long
#define VI vector<int>
#define VL vector<long long>
#define FOR(i,a,b) for(int i= (a); i<((int)b); ++i)
#define RFOR(i,a) for(int i=(a); i >= 0; --i)
#define FOE(i,a) for(auto i : a)
#define ALL(c) (c).begin(), (c).end()
#define RALL(c) (c).rbegin(), (c).rend()
#define DUMP(x)  cerr << #x << " = " << (x) << endl;
#define SUM(x) std::accumulate(ALL(x), 0LL)
#define MIN(v) *std::min_element(v.begin(), v.end())
#define MAX(v) *std::max_element(v.begin(), v.end())
#define EXIST(v,x) (std::find(v.begin(), v.end(), x) != v.end())
#define BIT(n) (1LL<<(n))
#define UNIQUE(v) v.erase(unique(v.begin(), v.end()), v.end());
#define INF INT_MAX / 3
#define EPS 1e-14

using namespace std;


struct Edge {
    int from;
    int to;
    int cost;
    Edge(int from, int to, int cost): from(from), to(to), cost(cost){};
    bool operator<(const Edge& edge) const {
        return this->cost < edge.cost;
    }
    bool operator>(const Edge& edge) const {
        return this->cost > edge.cost;
    }
};

class UnionFind {
public:
    vector<int> parent;

    UnionFind(int size) {
        parent.resize(size + 1);
        iota(parent.begin(), parent.end(), 0);
    }

    // xとyが同じ集合に属するか
    bool isSameSet(int x, int y) {
        return findRoot(x) == findRoot(y);
    }

    // xとyの属する集合を併合
    void unionSet(int x, int y) {
        x = findRoot(x);
        y = findRoot(y);
        if (x == y) { return; }

        parent[x] = y;
    }

    // 集合の数を取得
    int getNumberOfSet() {
        int n = 0;
        for (int i = 0; i < parent.size(); ++i) {
            if (parent[i] == i) { n++; }
        }
        return n;
    }

private:
    // 木の根を求める
    int findRoot(int x) {
        if (parent[x] == x) {
            return x;
        }
        else {
            return parent[x] = findRoot(parent[x]);
        }
    }
};

/**
 * 最小全域木のコストを算出
 * @param V ノード数 
 * @param edges エッジ
 * @return 最小全域木のコスト
 */
int kruskal(int V, vector<Edge> edges) {
    sort(edges.begin(), edges.end());   // コストでソート
    
    UnionFind uf(V);
    int res = 0;
    for (Edge e : edges) {
        // 閉路にならないことをチェック
        if (!uf.isSameSet(e.from, e.to)) {
            uf.unionSet(e.from, e.to);
            res += e.cost;
        }
    }
    return res;
}


int main(int argc, char *argv[]) {
    cin.tie(0);
    ios::sync_with_stdio(false);
    int N, x, y;

    cin >> N;
    vector<pair<int, int>> xList, yList;
    FOR(i, 0, N) {
        cin >> x >> y;
        xList.push_back({x, i});
        yList.push_back({y, i});
    }
    sort(ALL(xList));
    sort(ALL(yList));
    
    vector<Edge> edges;
    FOR(i, 1, xList.size()) {
        edges.push_back(Edge(xList[i - 1].second, xList[i].second, abs(xList[i - 1].first - xList[i].first)));
        edges.push_back(Edge(xList[i].second, xList[i - 1].second, abs(xList[i - 1].first - xList[i].first)));
        edges.push_back(Edge(yList[i - 1].second, yList[i].second, abs(yList[i - 1].first - yList[i].first)));
        edges.push_back(Edge(yList[i].second, yList[i - 1].second, abs(yList[i - 1].first - yList[i].first)));
    }
    
    std::cout << kruskal(N, edges) << std::endl;
    return 0;
}

Measured memory_bytes: 13280