// Slower C++ solution:
#include <bits/stdc++.h>

#define f first

#define s second

using namespace std;

const int N = 2e5+5;

int n, par[N], sz[N];

vector<pair<int, int>> x, y;

int find(int x)

{

	return (par[x] == x? x : par[x] = find(par[x]));

}

void Union(int x, int y)

{

	if(sz[x] < sz[y]) swap(x, y);

	sz[x] += sz[y];

	par[y] = x;

}

int main()

{

	iota(par, par+N, 0);

	fill(sz, sz+N, 1);

	cin >> n;

	for(int i=0, a, b; i<n; i++)

	{

		cin >> a >> b;

		x.push_back({a, i});

		y.push_back({b, i});

	}

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

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

	priority_queue<pair<int, pair<int, int>>> q;

	for(int i=0; i<n-1; i++) q.push({x[i].f-x[i+1].f, {x[i].s, x[i+1].s}}),

	q.push({y[i].f-y[i+1].f, {y[i].s, y[i+1].s}});

	int ans = 0;

	while(!q.empty())

	{

		auto t = q.top();

		int cost = -t.f;

		int u = find(t.s.f), v = find(t.s.s);

		q.pop();

		if(u == v) continue;

		Union(u, v);

		ans += cost;

	}

	cout << ans << endl;	

		

}

// Faster C++ solution for the same problem (measured speedup: 2.5857028362327785x):
#define _USE_MATH_DEFINES

#include <algorithm>

#include <array>

#include <bitset>

#include <cassert>

#include <cctype>

#include <climits>

#include <clocale>

#include <cmath>

#include <cstdio>

#include <cstdlib>

#include <ctime>

#include <deque>

#include <fstream>

#include <functional>

#include <iomanip>

#include <iostream>

#include <iterator>

#include <list>

#include <map>

#include <numeric>

#include <queue>

#include <regex>

#include <set>

#include <sstream>

#include <stack>

#include <string>

#include <tuple>

#include <unordered_map>

#include <unordered_set>

#include <utility>

#include <vector>



using namespace std;



#define IOS ios::sync_with_stdio(false); cin.tie(0);

#define FOR(i, s, n) for(int i = (s), i##_len=(n); i < i##_len; ++i)

#define FORS(i, s, n) for(int i = (s), i##_len=(n); i <= i##_len; ++i)

#define VFOR(i, s, n) for(int i = (s); i < (n); ++i)

#define VFORS(i, s, n) for(int i = (s); i <= (n); ++i)

#define REP(i, n) FOR(i, 0, n)

#define REPS(i, n) FORS(i, 0, n)

#define VREP(i, n) VFOR(i, 0, n)

#define VREPS(i, n) VFORS(i, 0, n)

#define RFOR(i, s, n) for(int i = (s), i##_len=(n); i >= i##_len; --i)

#define RFORS(i, s, n) for(int i = (s), i##_len=(n); i > i##_len; --i)

#define RREP(i, n) RFOR(i, n, 0)

#define RREPS(i, n) RFORS(i, n, 0)

#define LLFOR(i, s, n) for(ll i = (s), i##_len=(n); i < i##_len; ++i)

#define LLFORS(i, s, n) for(ll i = (s), i##_len=(n); i <= i##_len; ++i)

#define LLVFOR(i, s, n) for(ll i = (s); i < (n); ++i)

#define LLVFORS(i, s, n) for(ll i = (s); i <= (n); ++i)

#define LLREP(i, n) LLFOR(i, 0, n)

#define LLREPS(i, n) LLFORS(i, 0, n)

#define LLVREP(i, n) LLVFOR(i, 0, n)

#define LLVREPS(i, n) LLVFORS(i, 0, n)

#define LLRFOR(i, s, n) for(ll i = (s). i##_len=(n); i >= i##_len; --i)

#define LLRFORS(i, s, n) for(ll i = (s), i##_len=(n); i > i##_len; --i)

#define LLRREP(i, n) LLRFOR(i, n, 0)

#define LLRREPS(i, n) LLRFORS(i, n, 0)

#define IREP(i, v) for(auto i = (v).begin(); i != (v).end(); ++i)

#define IRREP(i, v) for(auto i = (v).rbegin(); i != (v).rend(); ++i)

#define ALL(v) (v).begin(), (v).end()

#define RALL(v) (v).rbegin(), (v).rend()

#define SORT(v) sort(ALL(v))

#define RSORT(v) sort(RALL(v))

#define SZ(x) ((int)(x).size())

#define REV(x) reverse(ALL(x))

#define PB push_back

#define EB emplace_back

#define MP make_pair

#define MT make_tuple

#define BIT(n) (1LL<<(n))

#define UNIQUE(v) v.erase(unique(ALL(v)), v.end())



using ld = long double;

using ll = long long;

using ui = unsigned int;

using ull = unsigned long long;

using Pi_i = pair<int, int>;

using Pll_ll = pair<ll, ll>;

using VB = vector<bool>;

using VC = vector<char>;

using VD = vector<double>;

using VI = vector<int>;

using VLL = vector<ll>;

using VS = vector<string>;

using VSH = vector<short>;

using VULL = vector<ull>;



const int MOD = 1000000007; 

const int INF = 1000000000; //1e9

const int NIL = -1;

const ll LINF = 1000000000000000000; // 1e18

const double EPS = 1E-10;



template<class T, class S>

bool chmax(T &a, const S &b){

    if(a < b){

        a = b; return true;

    }

    return false;

}

template<class T, class S>

bool chmin(T &a, const S &b){

    if(b < a){

        a = b; return true;

    }

    return false;

}







struct edge{

    int from, to, cost;

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

};



//UnionFind

class UnionFind{

    vector<int> par;

    vector<int> rank;

    vector<int> membnum;



public:

    UnionFind(){}

    UnionFind(int n): par(n), rank(n), membnum(n){

        REP(i, n){

            par[i] = i;

            rank[i] = 0;

            membnum[i] = 1;

        }

    }



    void resize(int n){

        int m = par.size();

        par.resize(n);

        rank.resize(n, 0);

        membnum.resize(n, 1);

        FOR(i, m, n) par[i] = i;

    }



    int find(int x){

        if(x == par[x]) return x;

        else return par[x] = find(par[x]);

    }



    void unit(int x, int y){

        x = find(x);

        y = find(y);

        if(x == y) return;



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

            par[x] = y;

            membnum[y] += membnum[x];

        }else{

            par[y] = x;

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

            membnum[x] += membnum[y];

        }

    }



    bool same(int x, int y){

        return find(x) == find(y);

    }



    int howmany(int x){ //同じグループに属すものの個数(自分を含む)

        return membnum[find(x)];

    }

};





int kruskal(vector<edge>& G){

    int V(G.size());

    sort(ALL(G), [](const edge& e1, const edge& e2){

        return e1.cost < e2.cost;

    });

    int res = 0;

    UnionFind UF(V);

    for(edge &e: G){

        if(!UF.same(e.from, e.to)){

            UF.unit(e.from, e.to);

            res += e.cost;

        }

    }

    return res;

}





int main(){

    int N; cin >> N;

    vector<edge> G;

    //x,y,idx と y,x,id

    vector<pair<Pi_i, int>> px(N), py(N);

    REP(i, N){

        px[i].second = py[i].second = i;

        cin >> px[i].first.first >> px[i].first.second;

        py[i].first.first = px[i].first.second;

        py[i].first.second = px[i].first.first;

    }

    SORT(px); SORT(py);

    REP(i, N-1){

        G.push_back({px[i].second, px[i+1].second, 

                    abs(px[i].first.first - px[i+1].first.first)});

        G.push_back({py[i].second, py[i+1].second, 

                    abs(py[i].first.first - py[i+1].first.first)});

    }

    cout << kruskal(G) << endl;

    return 0;

}