// Original C++ solution (slower):
#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

typedef pair<ll, ll> P;



int N;

vector<P> x, y;

vector<vector<P>> graph(100001); //辺のコスト、行先の頂点

bitset<100001> bit;//各点を一度使ったかどうか



ll Prim(int start = 1){

    

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

    que.push(make_pair(0, start)); //頂点startから始める

    

    ll num = 0;

    while(!que.empty()){

        ll cost, next; tie(cost, next) = que.top(); que.pop();

        if(bit[next]) continue;

        bit[next] = true;

        num += cost;

        for(int i = 0; i < graph[next].size(); ++i) que.push(graph[next][i]);

    }

    

    return num;

}



int main(void){

	

	scanf("%d", &N);

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

	    ll a, b; scanf("%lld %lld", &a, &b);

	    x.push_back(make_pair(a, i)), y.push_back(make_pair(b, i));

	}

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

	

	for(int i = 0; i < x.size() - 1; ++i){

	    int t1 = x[i].second, t2 = x[i + 1].second;

	    ll c = abs(x[i].first - x[i + 1].first);

	    graph[t1].push_back(make_pair(c, t2));

	    graph[t2].push_back(make_pair(c, t1));

	}

	

	for(int i = 0; i < y.size() - 1; ++i){

	    int t1 = y[i].second, t2 = y[i + 1].second;

	    ll c = abs(y[i].first - y[i + 1].first);

	    graph[t1].push_back(make_pair(c, t2));

	    graph[t2].push_back(make_pair(c, t1));

	}

	

	printf("%lld\n", Prim());

	

    return 0;

}


// Optimized solution to the same problem (faster):
#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

typedef pair<ll, ll> P;

typedef tuple<ll, ll, ll> T;



int N;

vector<P> x, y;

vector<T> graph; //辺のコスト、行先の頂点



class UnionFind {

	public:

		vector<int> par, rank;

 		

		void init(int n) {

			par = vector<int>(n + 1);

			rank = vector<int>(n + 1);

			for (int i = 0; i < n; i++) par[i] = i, rank[i] = 0;

		}

		// 木の根を求める

		int root(int x) {

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

		}

		// xとyの属する集合を併合

		void unite(int x, int y) {

			x = root(x), y = root(y);

			if (x == y)return;

 

			if (rank[x] < rank[y]) par[x] = y;

			else {

				par[y] = x;

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

			}

		}

		// xとyが同じ集合に属するか否か

		bool same(int x, int y) {

			return root(x) == root(y);

		}

};



ll Kruscal(){

    

    UnionFind uf;

    uf.init(N);

    

    ll ans = 0;

    for(auto g : graph){

        ll x, y, c; tie(c, x, y) = g;

        

        if(uf.root(x) != uf.root(y)){

            uf.unite(x, y);

            ans += c;

        }

        

    }

    

    return ans;

}



int main(void){

	

	scanf("%d", &N);

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

	    ll a, b; scanf("%lld %lld", &a, &b);

	    x.push_back(make_pair(a, i)), y.push_back(make_pair(b, i));

	}

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

	

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

	    graph.push_back(make_tuple(x[i + 1].first - x[i].first, x[i].second, x[i + 1].second));

	    graph.push_back(make_tuple(y[i + 1].first - y[i].first, y[i].second, y[i + 1].second));

	}

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

	

	printf("%lld\n", Kruscal());

	

    return 0;

}


// Fastest known solution for this problem: