// Slower C++ solution:
#include <iostream>

#include <vector>

#include <string>

#include <cstring>

#include <algorithm>

#include <cmath>

#include <set>

#include <map>

#include <queue>

#include <iomanip>

#include <cassert>

#include <random>

#include <tuple>



#define rep(i,n) for (int i = 0; i < (n); ++i)



using namespace std;

typedef long long ll;

typedef pair<int, int> P;



struct edge {int to; int cost;};

vector<edge> g[100100];

int dist[100100];

bool memo[100100];

const int INF = 1100100100;





void prim(int v) {

    priority_queue<P, vector<P>, greater<P> > q;

    fill(dist, dist+100100, INF);

    dist[v] = 0;

    q.push(P(0, v));

    while (!q.empty()) {

        P p = q.top(); q.pop();

        int cost = p.first;

        int node = p.second;

        memo[node] = 1;

        if (cost > dist[node]) continue;

        for (auto e: g[node]) {

            if (dist[e.to] > e.cost && !memo[e.to]) {

                dist[e.to] = e.cost;

                q.push(P(e.cost, e.to));

            }

        }

    }

}



int main() {

    int n;

    cin >> n;

    vector<P> x(n), y(n);

    rep(i,n) {

        cin >> x[i].first >> y[i].first;

        x[i].second = i;

        y[i].second = i;

    }

    

    sort(x.begin(), x.end());

    rep(i,n-1) {

        g[x[i].second].push_back({x[i+1].second, x[i+1].first - x[i].first});

        g[x[i+1].second].push_back({x[i].second, x[i+1].first - x[i].first});

    }



    sort(y.begin(), y.end());

    rep(i,n-1) {

        g[y[i].second].push_back({y[i+1].second, y[i+1].first - y[i].first});

        g[y[i+1].second].push_back({y[i].second, y[i+1].first - y[i].first});

    }



    prim(0);

    int all_cost = 0;

    rep(i,n) all_cost += dist[i];

    cout << all_cost << endl;



    return 0;

}


// Faster C++ solution for the same problem (measured speedup: 3.898341081968722x):
#include <iostream>

#include <vector>

#include <string>

#include <cstring>

#include <algorithm>

#include <cmath>

#include <set>

#include <map>

#include <stack>

#include <queue>

#include <iomanip>

#include <cassert>

#include <random>

#include <tuple>

#include <cstdint>

#include <complex>

#include <bitset>



#define rep(i,n) for (int i = 0; i < (n); ++i)



using namespace std;

typedef long long ll;

typedef pair<int, int> pint;



const int INF = 1 << 30;

const ll LINF = 1LL << 60;

const int MOD = 1e9 + 7;



int dx[] = {0, 0, 1, -1};

int dy[] = {1, -1, 0, 0};



class UnionFind {

public:

    int n;

    vector<int> parent;

    vector<int> rank;

    UnionFind(int m) {

        n = m;

        parent.resize(n);

        rank.resize(n, 0);

        for (int i = 0; i < n; i++) {

            parent[i] = i;

        }

    }



    int find(int node) {

        if (parent[node] == node) {

            return node;

        } else {

            parent[node] = find(parent[node]);

            return parent[node];

        }

    }



    void unite(int node1, int node2) {

        node1 = find(node1);

        node2 = find(node2);

        if (node1 == node2) {

            return;

        } else {

            if (rank[node1] < rank[node2]) {

                parent[node1] = node2;

            } else if (rank[node1] > rank[node2]) {

                parent[node2] = node1;

            } else {

                parent[node1] = node2;

                rank[node1] += 1;

            }

        }

    }



    bool same(int node1, int node2) {

        node1 = find(node1);

        node2 = find(node2);

        if (node1 == node2) {

            return true;

        } else {

            return false;

        }

    }

};



struct edge{

    int to, from, cost;

    edge(int to, int from, int cost): to(to), from(from), cost(cost) { };

};



bool compare(const edge& e1, const edge& e2) {

    return e1.cost < e2.cost;

}



int main() {

    int n; cin >> n;

    vector<edge> graph;

    vector<pint> X, Y;

    rep(i, n) {

        int x, y; cin >> x >> y;

        X.push_back(make_pair(x, i));

        Y.push_back(make_pair(y, i));

    }

    sort(X.begin(), X.end());

    sort(Y.begin(), Y.end());

    rep(i, n-1) {

        int u = X[i].second;

        int v = X[i+1].second;

        int cost = X[i+1].first - X[i].first;

        graph.push_back(edge(u, v, cost));

    }

    rep(i, n-1) {

        int u = Y[i].second;

        int v = Y[i+1].second;

        int cost = Y[i+1].first - Y[i].first;

        graph.push_back(edge(u, v, cost));

    }



    sort(graph.begin(), graph.end(), compare);



    UnionFind uf(n);

    ll ans = 0;

    rep(i, graph.size()) {

        int u = graph[i].to;

        int v = graph[i].from;

        int cost = graph[i].cost;

        if (uf.same(u, v)) continue;

        uf.unite(u, v);

        ans += cost;

    }



    cout << ans << endl;





    return 0;

}