#include <iostream>
#include <vector>
#include <cmath>
#include <tuple>
#include <algorithm>
using namespace std;
#pragma warning (disable: 4996)

vector<tuple<int, int, int>> cand;
int N, X[1 << 17], Y[1 << 17];
int R[1 << 17], ID[1 << 17];
int INF = 1000000000;

void update(int p1, int p2) {
	int dst = max(abs(X[p1] - X[p2]), abs(Y[p1] - Y[p2]));
	if (R[p1] > dst) {
		R[p1] = dst;
		ID[p1] = p2;
	}
}

void calc(vector<int> V1, vector<int> V2) {
	if (V1.size() == 0 || V2.size() == 0) return;

	// 計算する
	vector<tuple<int, int, int>> K(V1.size() + V2.size(), make_tuple(0, 0, 0));
	for (int i = 0; i < V2.size(); i++) K[i] = make_tuple(X[V2[i]], -Y[V2[i]], V2[i]);
	for (int i = 0; i < V1.size(); i++) K[i + V2.size()] = make_tuple(X[V1[i]], -Y[V1[i]] - INF, -V1[i]);
	sort(K.begin(), K.end());

	vector<pair<int, int>> E;
	for (int i = K.size() - 1; i >= 0; i--) {
		if (get<2>(K[i]) < 0) {
			int pos = -get<2>(K[i]);
			int pos1 = lower_bound(E.begin(), E.end(), make_pair(Y[pos] - X[pos], -INF)) - E.begin();

			if (pos1 >= 1) {
				update(pos, E[pos1 - 1].second);
			}
			if (pos1 < E.size()) {
				update(pos, E[pos1].second);
			}
		}
		else {
			while (E.size() >= 1) {
				int vx = X[E[E.size() - 1].second], vy = Y[E[E.size() - 1].second];
				if (vy > -get<1>(K[i])) E.pop_back();
				else break;
			}
			E.push_back(make_pair(-get<1>(K[i]) - get<0>(K[i]), get<2>(K[i])));
		}
	}
	
	// 分割する
	vector<int> G1; for (int i = 0; i < V1.size() / 2; i++) G1.push_back(V1[i]);
	vector<int> G2; for (int i = V1.size() / 2; i < V1.size(); i++) G2.push_back(V1[i]);
	calc(G1, G2);

	vector<int> H1; for (int i = 0; i < V2.size() / 2; i++) H1.push_back(V2[i]);
	vector<int> H2; for (int i = V2.size() / 2; i < V2.size(); i++) H2.push_back(V2[i]);
	calc(H1, H2);
}

void Solve() {
	vector<tuple<int, int, int>> tup;
	for (int i = 1; i <= N; i++) {
		tup.push_back(make_tuple(Y[i], X[i], i));
		R[i] = (1 << 30); ID[i] = -1;
	}
	sort(tup.begin(), tup.end());

	vector<int> L1; for (int i = 0; i < N / 2; i++) L1.push_back(get<2>(tup[i]));
	vector<int> L2; for (int i = N / 2; i < N; i++) L2.push_back(get<2>(tup[i]));

	calc(L1, L2);

	for (int i = 1; i <= N; i++) {
		if (ID[i] == -1) continue;

		int pos = ID[i];
		int dst = max(abs(X[i] - X[pos]), abs(Y[i] - Y[pos]));
		cand.push_back(make_tuple(dst, i, pos));
	}
}

class UnionFind {
public:
	vector<int> par;

	void init(int sz) {
		par.resize(sz, -1);
	}
	int root(int pos) {
		if (par[pos] == -1) return pos;
		par[pos] = root(par[pos]);
		return par[pos];
	}
	void unite(int u, int v) {
		u = root(u); v = root(v);
		if (u != v) { par[u] = v; }
	}
	bool same(int u, int v) {
		if (root(u) == root(v)) return true;
		return false;
	}
};

int main() {
	scanf("%d", &N);
	for (int i = 1; i <= N; i++) scanf("%d%d", &X[i], &Y[i]);

	// ステップ 1 : 分割統治法を用いて候補点を考える
	for (int i = 0; i < 4; i++) {
		Solve();
		if (i == 0 || i == 2) { for (int j = 1; j <= N; j++) X[j] *= -1; }
		if (i == 1 || i == 3) { for (int j = 1; j <= N; j++) Y[j] *= -1; }
	}
	sort(cand.begin(), cand.end());

	// ステップ 2 : クラスカル法をする
	UnionFind UF; UF.init(N + 2);

	long long FinalAns = 0;
	for (int i = 0; i < cand.size(); i++) {
		if (UF.same(get<1>(cand[i]), get<2>(cand[i])) == false) {
			FinalAns += 1LL * get<0>(cand[i]);
			UF.unite(get<1>(cand[i]), get<2>(cand[i]));
		}
	}
	cout << FinalAns << endl;
	return 0;
}


Measured memory_bytes: 15904