#include <bits/stdc++.h>
using ll = long long;
using namespace std;
#define rep(i,n) for(int i=0, i##_len=(int)(n); i<i##_len; i++)
#define reps(i,n) for(int i=1 , i##_len=(int)(n);i<=i##_len;i++)
#define rrep(i,n) for(int i=((int)(n)-1);i>=0;i--)
#define rreps(i,n) for(int i=((int)(n));i>0;i--)
#define repi(i,x) for(auto i=(x).begin(),i##_fin=(x).end();i!=i##_fin;i++)
#define all(x) (x).begin(), (x).end()
#define F first
#define S second
#define mp make_pair
#define pb push_back
#define solve(a) ((a)?"Yes":"No")
typedef vector<int> Vi;
typedef vector<Vi> VVi;
typedef pair<int , int> Pi;
typedef vector<Pi> VPi;
typedef vector<long long> V;
typedef vector<V> VV;
typedef pair<long long , long long> P;
typedef vector<P> VP;
template<class T> inline bool chmax(T& a, T b) { if (a < b) { a = b; return 1;} return 0;}
template<class T> inline bool chmin(T& a, T b) { if (a > b) { a = b; return 1;} return 0;}
const long long INFLL = 1LL<<60;
const int INF = 1<<30;
const double PI=acos(-1);
//union by size + path having
class UnionFind{
	public:
	vector<long long> par; // 各元の親を表す配列
	vector<long long> siz; // 素集合のサイズを表す配列(1 で初期化)


	// Constructor
	UnionFind(long long sz_) : par(sz_), siz(sz_,1LL){
		for (long long i = 0; i < sz_; ++i)
		par[i] = i; // 初期では親は自分自身
	}
	void init(long long sz_){
		par.resize(sz_);
		siz.assign(sz_,1LL); // resize だとなぜか初期化されなかった
		for (long long i = 0; i < sz_; ++i)
			par[i] = i; // 初期では親は自分自身
	}
	// Member Function


	// Find
	long long root(long long x){ // 根の検索
		while (par[x] != x){
			x = par[x] = par[par[x]]; // x の親の親を x の親とする
		}
		return x;
	}
	// 結合(Unite, Merge)
	bool merge(long long x, long long y){
		x = root(x);
		y = root(y);
		if (x == y){
			return false;
		}
		// merge technique（データ構造をマージするテク．小を大にくっつける）
		if (siz[x] < siz[y]){
			swap(x, y);
		}
		siz[x] += siz[y];
		par[y] = x;
		return true;
	}


	// 連結判定(つながっているときはture,つながっていなければfalse)
	bool issame(long long x, long long y){ 
		return root(x) == root(y);
	}


	// 素集合のサイズ
	long long size(long long x){ 
		return siz[root(x)];
	}
};
//include UnionFind

//クラスカル法(隣接リストから最小全域木を隣接リストで返す)
//計算量 (辺)log(頂点)
vector<vector<pair<int, long long>>>Kruskal(vector<vector<pair<int,long long>>>pathlist){
	vector<pair<long long, pair<int, int>>> paths;
	int edge=pathlist.size();
	UnionFind conect(edge);
	vector<vector<pair<int, long long>>> res(edge);
	rep(i, edge){
		for (auto itr = pathlist[i].begin(); itr != pathlist[i].end(); itr++){
			paths.emplace_back(itr->second, make_pair(i, itr->first));
		}
	}
	sort(paths.begin(),paths.end());
	for (auto at = paths.begin(); at != paths.end(); at++){
		if (conect.merge(at->second.first, at->second.second)){
			res[at->second.first].emplace_back(at->second.second, at->first);
			res[at->second.second].emplace_back(at->second.first, at->first);
			if (conect.size(0) == edge){
				break;
			}
		}
	}
	return res;
}
int main(){
	int n;
	ll ans=0;
	cin >>n;
	vector<tuple<ll,ll,int>>data(n);
	vector<vector<pair<int,ll>>>path(n);
	ll y,x;
	rep(i,n){
		cin>>x>>y;
		data[i]=make_tuple(x,y,i);
	}
	sort(all(data));
	int s,t;
	ll c;
	rep(i,n-1){
		s=get<2>(data[i]);
		t=get<2>(data[i+1]);
		c = min(abs(get<0>(data[i]) - get<0>(data[i + 1])), abs(get<1>(data[i]) - get<1>(data[i + 1])));
		path[s].emplace_back(t,c);

		if (i == n - 2)
		{
			path[t].emplace_back(s, c);
		}
	}
	rep(i,n){
		x=get<0>(data[i]);
		y=get<1>(data[i]);
		data[i]=make_tuple(y,x,get<2>(data[i]));
	}
	sort(all(data));
	rep(i, n - 1)
	{
		s = get<2>(data[i]);
		t = get<2>(data[i+1]);
		c = min(abs(get<0>(data[i]) - get<0>(data[i + 1])), abs(get<1>(data[i]) - get<1>(data[i + 1])));
		path[s].emplace_back(t, c);
		if(i==n-2){
		path[t].emplace_back(s, c);
		}
	}
	
	vector<vector<pair<int, long long>>>res=Kruskal(path);
	rep(i,n){
		repi(itr,res[i]){
		//	clog<<(itr->F)<<endl;
			ans+=(itr->S);
		}
	}
	cout << ans/2 << endl;
}

Measured memory_bytes: 30700