#include <bits/stdc++.h>
using namespace std;
//=====================================================
// マクロ定義部
//=====================================================

#define FOR(i,a,b) for(ll i = (a); i < (b); ++i)
#define FOR_EQ(i,a,b) for(ll i = (a); i <= (b); ++i)
#define rep(i,n) FOR(i,0,n)
#define rep_eq(i,n) FOR_EQ(i,0,n)
#define DEBUG_VARIABLE(variable) cout << #variable << ":" << variable << endl
#define INFTY 1000000000000000000 // 10^18
#define WHITE 1//（未訪問）
#define GRAY 2//（訪問）未だに訪問していない頂点への辺を持っている。スタックに退避。
#define BLACK 3//（訪問完了）未訪問への頂点への辺を持たない
//=====================================================
// 型定義部
//=====================================================

typedef unsigned long long ull;
typedef long long ll;
typedef pair<ll, ll>    ll_ll;
typedef vector<ll> Vector;
typedef vector<Vector> DVector;
typedef vector< pair<ll, ll> > Vec_Pair;
template<class T>bool chmax(T &a, const T &b) { if (a<b) { a=b; return 1; } return 0 ;}
template<class T>bool chmin(T &a, const T &b) { if (b<a) { a=b; return 1; } return 0 ;}
//===================================================
// 関数のプロトタイプ宣言・関数に必要な配列の宣言
//===================================================

template <class X> void printArray(X *array, ll);
template <class X> void printVector(vector<X> &v);
template <class X> void printDimention(vector< vector<X> > &dv);
template <class X> void printMap(X);
template <class X> void printVecPair(vector<X> &v);
void printDV_Pair(vector<vector<pair<ll, ll> > > &v);
void printSet(set<ll> &S);
// 繰返し自乗法
ll RepeatSquaring(ll a, ll index);
// 繰返し自乗法 MOD
ll RepeatSquaring_MOD(ll a, ll index, ll M);
// 最大公約数
ll GCD(ll, ll);
// 最小公倍数
ll LCM(ll, ll);
// 割り算した時に余りが有る時だけ、+1の商を返す。
ll div_one(ll res, ll div);

//===================================================
// グローバル
//===================================================

const int MOD = 1000000007;
//1個上から時計周り
const int ddx[8] = {0, 1, 1, 1, 0, -1, -1, -1};
const int ddy[8] = {1, 1, 0, -1, -1, -1, 0, 1};
//上右下左
const int dx[4] = {0, 1, 0, -1};    // dj
const int dy[4] = {-1, 0, 1, 0};    // di
static const int NIL = -1;

ll N, k, K, V, E;

//===================================================
// 関数
//===================================================

typedef struct _point {
    ll id, x, y;
} Point;

bool compx(const Point &a, const Point &b){
    if(a.x != b.x){
        return a.x < b.x;
    }else{
        return a.y < b.y;
    }
}

bool compy(const Point &a, const Point &b){
    if(a.y != b.y){
        return a.y < b.y;
    }else{
        return a.x < b.x;
    }
}

typedef struct _path {
    ll id1, id2, cost;

    _path(ll arg1, ll arg2, ll arg3){
        id1 = arg1; id2 = arg2; cost = arg3;
    }

    bool operator < (const struct _path &arg) const {
        return cost < arg.cost;
    }
} Path;

struct UnionFind {
    vector<int> par; // par[i]:iの親の番号　(例) par[3] = 2 : 3の親が2
    vector<int> r_size; //頂点vが何個の頂点を従えているか（自身を含む）
    
    //コンストラクタで初期化
    UnionFind(int n) : par(n), r_size(n) { //最初は全てが根であるとして初期化
        for(int i = 0; i < n; i++){
            par[i] = i; //vectorのassignを使ってもいいかもしれない
        }
        r_size.assign(n, 1);
    }

    int root(int x) { // データxが属する木の根を再帰で得る：root(x) = {xの木の根}
        if (par[x] == x) return x;
        // 経路圧縮
        return par[x] = root(par[x]); //これで根を貼り直してる．巧妙なテクニックや...
    }

    void unite(int x, int y) { // xとyの木を併合
        int rx = root(x); //xの根をrx
        int ry = root(y); //yの根をry
        if (rx == ry) return; //xとyの根が同じ(=同じ木にある)時はそのまま
        
        //par[rx] = ry; //xとyの根が同じでない(=同じ木にない)時：xの根rxをyの根ryにつける
        // xとyの根が同じでない(=同じ木にない)時：サイズが小さい方の根をサイズが大きい方の根につける
        if(r_size[rx] < r_size[ry]){
            par[rx] = ry;
            r_size[ry] += r_size[rx];
        }else{
            par[ry] = rx;
            r_size[rx] += r_size[ry];
        }
    }

    bool same(int x, int y) { // 2つのデータx, yが属する木が同じならtrueを返す
        int rx = root(x);
        int ry = root(y);
        return rx == ry;
    }
    
    //
    int size(int x){
        return r_size[root(x)];
    }
};

ll min_cost;
vector<Path> pa;

void kruskal(UnionFind uf){
    
    rep(i, pa.size()){
        ll a = pa[i].id1, b = pa[i].id2;

        // 同じグループじゃない → このエッジは追加してよい
        if(!uf.same(a, b)){
            min_cost += pa[i].cost;
            uf.unite(a, b);
        }
    }
}

void kruskal_init(){
    sort(pa.begin(), pa.end());

    /*
    rep(i, pa.size()){
        cout << pa[i].id1 << " " << pa[i].id2 << " " << pa[i].cost << endl;
    }
    */
    UnionFind uf(N);
    kruskal(uf);
}

//===================================================
// main 問題処理部
//===================================================
int main(int argc, char const *argv[])
{
    cin.tie(0);
    ios::sync_with_stdio(false);

    cin >> N;
    vector<Point> po(N);

    rep(i, N){
        cin >> po[i].x >> po[i].y;
        po[i].id = i;
    }

    sort(po.begin(), po.end(), compx);

    rep(i, N){
        ll bfe, aft;
        if(i > 0){
            bfe = i - 1;
            ll cost = min(abs(po[bfe].x - po[i].x), abs(po[bfe].y - po[i].y));
            pa.push_back(Path(po[bfe].id, po[i].id, cost));
        }

        if(i < N - 1){
            aft = i + 1;
            ll cost = min(abs(po[aft].x - po[i].x), abs(po[aft].y - po[i].y));
            pa.push_back(Path(po[aft].id, po[i].id, cost));
        }
    }

    sort(po.begin(), po.end(), compy);

    rep(i, N){
        ll bfe, aft;
        if(i > 0){
            bfe = i - 1;
            ll cost = min(abs(po[bfe].x - po[i].x), abs(po[bfe].y - po[i].y));
            pa.push_back(Path(po[bfe].id, po[i].id, cost));
        }

        if(i < N - 1){
            aft = i + 1;
            ll cost = min(abs(po[aft].x - po[i].x), abs(po[aft].y - po[i].y));
            pa.push_back(Path(po[aft].id, po[i].id, cost));
        }
    }

    kruskal_init();

    cout << min_cost << endl;

    return 0;
}

//=====================================================
// 関数群
//=====================================================

template<class X> void printArray(X array[], ll n){
    rep(i, n){
        if(i)   cout << " ";
        cout << array[i];
    }
    cout << endl;
}

template<class X> void printVector(vector<X> &v){
    rep(i, (int)v.size()){
        if(i)   cout << " ";
        cout << v[i];
    }
    cout << endl;
}

//二次元配列の表示
template<class X> void printDimention(vector< vector<X> > &dv){
    rep(i, (ll)dv.size()){
        rep(j, (ll)dv[i].size()){
            if(j)   cout << " ";
            cout << dv[i][j];
        }
        cout << endl;
    }
    cout << endl;
}

//mapの表示
template <class X> void printMap(X mp) {
    for (auto it : mp) {
        cout << it.first << " " << it.second << endl;
    }
}

// 内部にpairを内包したvectorの表示
template <class X> void printVecPair(vector<X> &v){
    rep(i, (int)v.size()){
        cout << v[i].first << " " << v[i].second << endl;
    }
    cout << endl;
}

// 内部にVec_Pairを内包したvectorの表示
void printDV_Pair(vector<vector<pair<ll, ll> > > &v){
    rep(i, (int)v.size()){
        cout << i << endl;
        rep(j, (int)v[i].size()){
            cout << v[i][j].first << " " << v[i][j].second << endl;
        }
        cout << endl;
    }
    cout << endl;
}

void printSet(set<ll> &S){
    for(set<ll>::iterator it = S.begin(); it != S.end(); it++){
        if(it != --S.end() ) cout << *it << " ";
        else    cout << *it << endl;
    }
}

ll RepeatSquaring(ll a, ll index){
    if(index == 0)  return  1;
    else if(index % 2 == 0){
        ll tmp = RepeatSquaring(a, index / 2);
        return tmp * tmp;
    }else{
        return a * RepeatSquaring(a, index - 1);
    }
}

/**
 * MODを使用した繰返し自乗法
 * a: 基数, index: 指数, M: MOD
 */
ll RepeatSquaring_MOD(ll a, ll index, ll M){
    // Nは基数、Pは指数、MはMOD
    if(index == 0)  return 1;
    if(index % 2 == 0){
        ll tmp = RepeatSquaring_MOD(a, index/2, M);
        return (tmp * tmp) % M;
    }else{
        return (a * RepeatSquaring_MOD(a, index - 1, M)) % M;
    }
}

//最大公約数(Greatest Common Divisor)
// ユークリッドの互除法使用。 0・負の数に対応
ll GCD (ll a, ll b){
    if(b == 0)  return abs(a);
    return  GCD(b, a % b);
}

//最小公倍数(Least Common Multiple)
ll LCM(ll m, ll n){
    //引数に0がある場合は0を返す
    if(m == 0 || n == 0)    return 0;

    //lcm = m * n / gcd(m, n)
    return ((m / GCD(m, n)) * n);
}

// 割り算した時に余りが有る時だけ、+1の商を返す。
ll div_one(ll res, ll div){
    // res 割られる数、div 割る数
    return (res + div - 1)/div;
}

Measured memory_bytes: 17900