#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <vector>
#include <map>
#include <unordered_map>
#include <iterator>
#include <iostream>
#include <algorithm>
using namespace std;

// 優先度付きキュー
class class_PrQue{
public:
	class_PrQue(){};
	virtual ~class_PrQue(){};
	bool Push(int to, int from, int64_t Cost);
	bool Pop(int &rtn_to, int &rtn_from, int64_t &rtn_Cost);
protected:
	multimap< int64_t , pair<int ,int > > Que_Cost; // cost < to , from >
	unordered_map<int , int64_t> Que_Num;	// 		<to, 	Cost	>
};

bool class_PrQue::Push(int to ,int from , int64_t Cost){
	auto qNum = Que_Num.find( to );
	if ( qNum != Que_Num.end()) {
		// 同一Key は存在する。

		if (qNum->second <= Cost){return false;}// 登録済みの方が 低コストのため 無変更

		//一旦削除

		// Que_Cost 側から削除
		auto p = Que_Cost.equal_range( qNum->second );
		for (auto it = p.first; it != p.second; ++it) {
			if (it->second.first == qNum->first){
				Que_Cost.erase(it);
				break;
			}
		}

		// Que_Num 側から削除
		Que_Num.erase(qNum);
	}

	// 登録
	Que_Cost.emplace(Cost, make_pair(to,from));
	Que_Num.emplace(to,Cost);
	return true;
}

bool class_PrQue::Pop(int &rtn_to, int &rtn_from, int64_t &rtn_Cost){
	auto topMean = Que_Cost.begin();
	if (topMean == Que_Cost.end()){
		// Que 内に存在しない。
		return false;
	}
	rtn_Cost = topMean->first;
	rtn_to = topMean->second.first;
	rtn_from = topMean->second.second;


	// Queから削除
	Que_Num.erase(Que_Num.find(rtn_to));
	Que_Cost.erase(Que_Cost.begin());
	return true;
}


// 最小被覆木（最小全域木）

struct Edge{int to; int64_t cost;};

class class_Prims{
public:
	class_Prims(){};
	virtual ~class_Prims(){};
	void init (int pointNum);
	void Set_1Way(int from , int to , int64_t cost){inGraph[from].insert(make_pair(to,cost));}
	void Set_2Way(int p1, int p2 , int64_t cost){Set_1Way(p1,p2,cost);Set_1Way(p2,p1,cost);}
	void Search(int startPoint);
	int64_t Get_SumLength(){return SumLengh;}

	vector< vector<Edge> > AnsTree;
	vector< int64_t > Depth;
	void Print_AnsTree();

protected:
	int PointNum=0;
	vector< map<int,int64_t> > inGraph; // map ならば Key(この場合 目的地) が同じものは登録されない
	int64_t SumLengh=0;
};


void class_Prims::init(int pointNum){
	PointNum = pointNum;
	inGraph.resize(pointNum);
	AnsTree.resize(pointNum);
	Depth.resize(pointNum);
}

void class_Prims::Print_AnsTree(){
	for(int i=0;i<PointNum;i++){
		printf("[%2d]: ",i);
		for(auto e: AnsTree[i]){
			printf(" ->[%d:(%ld)] ",e.to,e.cost);
		}
		printf("\n");
	}
}

void class_Prims::Search(int startPoint){
	vector<int> Color(PointNum);
	class_PrQue Que;
	SumLengh = 0;
	// 初期値格納
	for(auto next : inGraph[startPoint] ){
		Que.Push(next.first,startPoint,next.second);
		Color[next.first]=1;
	}
	Color[startPoint] = 2;

	while(1){
		int to;
		int from;
		int64_t cost;

		if (!Que.Pop(to,from,cost)){break;} // キューが空=探索し終えた

		AnsTree[from].push_back({to,cost}); // 結果 木構造に登録
		SumLengh += cost;
		Depth[to] = Depth[from] + cost;
		Color[to] = 2;

		for(auto next : inGraph[to] ){
			if (Color[next.first] == 2){continue;}
			Que.Push(next.first, to , next.second);
			Color[next.first] = 1;
		}
	}
}


struct struct_town{int n; int x; int y;};

int main(int argc , char **argv)
{
	(void)argc;
	(void)argv;

	class_Prims prims;
	int N;
	cin >> N;
	vector< struct_town > town(N+1);
	for(int i=1; i<=N; i++){
		town[i].n = i;
		cin >> town[i].x >> town[i].y;
	}

	prims.init(N+1);
//printf("--\n");

	// x 方向
	stable_sort(
			town.begin(),
			town.end(),
			[](struct_town const &L, struct_town const &R){return L.x < R.x;}
	);

	for(int i=2;i<=N;i++){
		int c = min( abs(town[i].x - town[i-1].x) , abs(town[i].y -town[i-1].y) );
		prims.Set_2Way(town[i].n , town[i-1].n , c);
//printf("town[%d](%d,%d) : town[%d](%d,%d) : cost :%d\n",i,town[i].x,town[i].y, i-1,town[i-1].x,town[i-1].y , c );
	}

//printf("--\n");
	// y 方向
	stable_sort(
			town.begin(),
			town.end(),
			[](struct_town const &L, struct_town const &R){return L.y < R.y;}
	);

	for(int i=2;i<=N;i++){
		int c = min( abs(town[i].x - town[i-1].x) , abs(town[i].y -town[i-1].y) );
		prims.Set_2Way(town[i].n , town[i-1].n , c);
//printf("town[%d](%d,%d) : town[%d](%d,%d) : cost :%d\n",i,town[i].x,town[i].y, i-1,town[i-1].x,town[i-1].y , c );

	}

	prims.Search(1);
//prims.Print_AnsTree();
//printf("--\n");
	printf("%ld\n",prims.Get_SumLength());

	return 0;
}


Measured memory_bytes: 40244