#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);
//include UnionFind
//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)];
	}
};
//クラスカル法(隣接リストから最小全域木を隣接リストで返す)
//計算量 (辺)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)){
		//	clog<<(at->S.F)<<" "<<(at->S.S)<<" "<<(at->F)<<endl;
			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, long long>>> path(n), res;
	int x, y;
	rep(i, n)
	{
		cin >> x >> y;
		data[i] = make_tuple(x, y, i);
	}
	int at;
	int to;
	ll cost;
	sort(all(data));
	for (int i = 0; i < n - 1; i++)
	{
		at = get<2>(data[i]);
		to = get<2>(data[i + 1]);
		cost = (ll)min(
			abs(get<0>(data[i]) - get<0>(data[i + 1])),
			abs(get<1>(data[i]) - get<1>(data[i + 1]))
			);
		path[at].emplace_back(to, cost);
		path[to].emplace_back(at, cost);
	}
	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));
	for (int i = 0; i < n - 1; i++)
	{
		at = get<2>(data[i]);
		to = get<2>(data[i + 1]);
		cost = (ll)min(
			abs(get<0>(data[i]) - get<0>(data[i + 1])),
			abs(get<1>(data[i]) - get<1>(data[i + 1])));
		path[at].emplace_back(to, cost);
		path[to].emplace_back(at, cost);
	}
	//
	/*
	rep(i, n)
	{
		repi(itr, path[i])
		{
		clog<<(itr->F)<<" -- "<<(itr->S)<<" ";
		}
		clog<<endl;
	}
	*/
	//
	pair<int ,ll>last=mp(INF,0LL);
	res = Kruskal(path);
	rep(i, n)
	{
		last = mp(INF, 0LL);
		sort(all(res[i]));
		repi(itr, res[i])
		{
		//	clog<<i<<" "<<(itr->F)<<" -- "<<(itr->S)<<endl;
			if(itr==res[i].begin())
			{
				ans+=(itr->S);
			}else if(((itr-1)->F) !=(itr->F)){
			ans += itr->S;
			}
			last=*itr;
		}
	}
	cout << ans / 2 << endl;
}
/*
4 9-----------------d
7 6 [3]abd
8 3 [1]a
12 19 [4]c
13 5 [1]cb
18 1 [5]-----------
 
{0,3,1,4,1,5}
{0,2,2,1,3,10}
 
18 1-------------e
8 3 [2]e
13 5 [2]b
7 6 [1]bd
4 9 [3]---------d
12 19 [10]
 
[7 6]-(1)-[8 3] [13 5]-(1)-[7 6] [12 19]-(1)-[13 5]
 
 [12 19]-(1)-[13 5]-(1)-[7 6] -(1)-[8 3]-(2)-[18 1]
								-(3)-[4 9]
*/

Measured memory_bytes: 40812