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

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

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

using P = pair<int,int>;



/* 大文字を小文字に変換 */

char tolower(char c) {return (c + 0x20);}

/* 小文字を大文字に変換 */

char toupr(char c) {return (c - 0x20);}



// if('A'<=s[i] && s[i]<='Z') s[i] += 'a'-'A';



/*

string s = "abcdefg"

s.substr(4) "efg"

s.substr(0,3) "abc"

s.substr(2,4) "cdef"



// イテレータ要素のインデックス

distance(A.begin(), itr);

*/



const int MAX_N = 100100;

const int WHITE = 0, GRAY = 1, BLACK = 2;

const int INF = 1000100100;



vector<P> to[MAX_N];

int d[MAX_N], p[MAX_N], color[MAX_N];

int N; 



class DisjointSet{

    public:

        vector<int> rank, p;

        // コンストラクタ

        DisjointSet(){}

        DisjointSet(int size){

            rank.resize(size,0);    // vectorのサイズを変更して、デフォルト値として0を代入している

            p.resize(size, 0);

            rep(i,size) makeSet(i);

        }



        // 入力値xのみの集合を作成する

        void makeSet(int x){

            p[x] = x;

            rank[x] = 0;

        }

        // ２つの入力要素が同じ集合か否かを判別する

        bool same(int x, int y){

            return findSet(x) == findSet(y);

        }

        // 2つの集合を結合する

        void unite(int x, int y){

            link(findSet(x), findSet(y));

        }



        void link(int x, int y){

            if(rank[x]>rank[y]){

                p[y] = x;

            }else{

                p[x] = y;

                if(rank[x] == rank[y]) rank[y]++;

            }

        }



        int findSet(int x){

            if(x != p[x]){

                // 経路圧縮をしている

                p[x] = findSet(p[x]);

            }

            // 親要素と自分の要素が一致したときに親を返す

            return p[x];

        }

};





class Edge {

    public:

        int source, target, cost;

        // コンストラクタ

        Edge(int source=0, int target=0, int cost=0):

        source(source), target(target), cost(cost) {}

        bool operator < (const Edge &e) const {

            return cost < e.cost;

        }

};



int kruskal(int N, vector<Edge> edges){

    int totalCost = 0;

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



    DisjointSet dset = DisjointSet(N+1);



    rep(i,N) dset.makeSet(i);



    int source, target;

    rep(i,edges.size()){

        Edge e = edges[i];

        if(!dset.same(e.source, e.target)){

            //MST.push_back(e);

            totalCost += e.cost;

            dset.unite(e.source, e.target);

        }

    }

    return totalCost;

}



int main()

{

    cin >> N;

    vector<P> p_x(N);

    vector<P> p_y(N);

    rep(i,N){

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

        // xまたはy座標と点の番号を格納する（ソートしてもわからなくならないため）

        p_x[i] = make_pair(x, i);

        p_y[i] = make_pair(y, i);

    }

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

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

    vector<Edge> edges;

    for(int i=1; i<N; i++){

        /*

        to[p_x[i].second].push_back(make_pair(p_x[i-1].second, p_x[i].first - p_x[i-1].first));

        to[p_x[i-1].second].push_back(make_pair(p_x[i].second, p_x[i].first - p_x[i-1].first));

        to[p_y[i].second].push_back(make_pair(p_y[i-1].second, p_y[i].first - p_y[i-1].first));

        to[p_y[i-1].second].push_back(make_pair(p_y[i].second, p_y[i].first - p_y[i-1].first));

        */

        edges.push_back(Edge(p_x[i].second, p_x[i-1].second, p_x[i].first - p_x[i-1].first));

        edges.push_back(Edge(p_x[i-1].second, p_x[i].second, p_x[i].first - p_x[i-1].first));

        edges.push_back(Edge(p_y[i].second, p_y[i-1].second, p_y[i].first - p_y[i-1].first));

        edges.push_back(Edge(p_y[i-1].second, p_y[i].second, p_y[i].first - p_y[i-1].first));



    }



    cout << kruskal(N, edges) << endl;

    return 0;

}

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

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

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

using P = pair<int,int>;

const int INF = 1000100100;



/* 大文字を小文字に変換 */

char tolower(char c) {return (c + 0x20);}

/* 小文字を大文字に変換 */

char toupr(char c) {return (c - 0x20);}



// if('A'<=s[i] && s[i]<='Z') s[i] += 'a'-'A';



/*

string s = "abcdefg"

s.substr(4) "efg"

s.substr(0,3) "abc"

s.substr(2,4) "cdef"



// イテレータ要素のインデックス

distance(A.begin(), itr);

*/



struct DisjointSet{

    vector<int> p;

    DisjointSet(int n): p(n){

        rep(i,n) p[i] = -1;

    }



    int root(int x){

        if(p[x]<0) return x;

        return p[x] = root(p[x]);

    }



    void unite(int x, int y){

        int rx = root(x);

        int ry = root(y);

        if(rx == ry) return;

        if(rx>ry) swap(rx,ry);

        p[rx] += p[ry];

        p[ry] = rx;

    }



    bool same(int x, int y){

        int rx = root(x);

        int ry = root(y);

        return rx == ry;

    }

};



int main()

{

    int n; cin >> n;

    vector<P> x;

    vector<P> y;

    rep(i,n){

        int xi, yi; cin >> xi >> yi;

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

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

    }

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

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



    priority_queue<tuple<int,int,int> > pq;



    rep(i,n-1){

        pq.push(make_tuple(-abs(x[i].first-x[i+1].first), x[i].second, x[i+1].second));

        pq.push(make_tuple(-abs(y[i].first-y[i+1].first), y[i].second, y[i+1].second));

    }



    DisjointSet dis = DisjointSet(n);

    ll ans = 0;

    while(!pq.empty()){

        int s, t, e;

        tie(e,s,t) = pq.top(); pq.pop(); e = -e;

        if(!dis.same(s,t)){

            ans += e;

            dis.unite(s,t);

        }

    }

    cout << ans << endl;

}