// Original C++ solution (slower):
#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;

}

// Optimized solution to the same problem (faster):
#include<iostream>

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

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

using P = pair<ll, ll>;



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

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<ll> p;

    DisjointSet(ll n) : p(n){

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

    }



    ll root(ll x){

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

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

    }



    void unite(ll x, ll y){

        ll rx = root(x);

        ll ry = root(y);

        if(rx == ry) return;

        p[ry] = rx;

    }



    bool same(ll x, ll y){

        ll rx = root(x);

        ll ry = root(y);

        return rx == ry;

    }

};





int main()

{

    ll n; cin >> n;

    vector<tuple<ll, ll, ll> > sortx;

    vector<tuple<ll, ll, ll> > sorty;

    rep(i,n){

        ll x, y; cin >> x >> y;

        sortx.push_back(make_tuple(x, y, i));

        sorty.push_back(make_tuple(y, x, i));

    }

    // cout << "ok" << endl;

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

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



    vector<tuple<ll, ll, ll> > eds;

    // cout << "ok2" << endl;

    rep(i,n-1){

        ll x_i0, y_i0, i0;

        ll x_i1, y_i1, i1;

        tie(x_i0, y_i0, i0) = sortx[i];

        tie(x_i1, y_i1, i1) = sortx[i+1];

        eds.push_back(make_tuple(x_i1-x_i0, i0, i1));

        tie(y_i0, x_i0, i0) = sorty[i];

        tie(y_i1, x_i1, i1) = sorty[i+1];

        eds.push_back(make_tuple(y_i1-y_i0, i0, i1));

    }

    // cout << "ok3" << endl;

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



    ll size_eds = eds.size();



    DisjointSet dis = DisjointSet(n);

    // cout << "ok4" << endl;

    ll ans = 0;



    rep(i,size_eds){

        ll w, s, t;

        tie(w, s, t) = eds[i];

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

            ans += w;

            dis.unite(s, t);

        }

    }

    // cout << "ok5" << endl;

    cout << ans << endl;

}

// Fastest known solution for this problem: