// Original C++ solution (slower):
#include "iostream"

#include "climits"

#include "list"

#include "queue"

#include "stack"

#include "set"

#include "functional"

#include "algorithm"

#include "math.h"

#include "utility"

#include "string"

#include "map"

#include "unordered_map"

#include "iomanip"

#include "random"



using namespace std;

const long long int MOD = 1000000007;

list<long long int> Prime(int M) {

	list<long long int>P;

	P.push_back(2);

	P.push_back(3);

	for (int i = 5; i <= M; i += 6) {

		bool flag = true;

		for (auto j : P) {

			if (i%j == 0) {

				flag = false;

				break;

			}

		}

		if (flag)P.push_back(i);

		flag = true;

		for (auto j : P) {

			if ((i + 2) % j == 0) {

				flag = false;

				break;

			}

		}

		if (flag)P.push_back(i + 2);

	}

	return P;

}

long long int power(long long int x, long long int n, long long int M) {

	long long int tmp = 1;



	if (n > 0) {

		tmp = power(x, n / 2, M);

		if (n % 2 == 0) tmp = (tmp*tmp) % M;

		else tmp = (((tmp*tmp) % M)*x) % M;

	}

	return tmp;

}



long long int N, M, K, Q, W, H;

long long int ans;



int da[200000];



int root(int x) {

	return da[x] < 0 ? x : da[x] = root(da[x]);

}

bool unionSet(int x, int y) {

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

	if (x != y) {

		if (da[y] < da[x]) swap(x, y);

		da[x] += da[y]; da[y] = x;

	}

	return  x != y;

}

bool findSet(int x, int y) {

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

}



int size(int x) {

	return -da[root(x)];

}



int main() {

	ios::sync_with_stdio(false);

	cin >> N;

	long long int x[100000];

	long long int y[100000];

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

		cin >> x[i] >> y[i];

		x[i] = x[i] * MOD + i;

		y[i] = y[i] * MOD + i;

	}

	for (int i = 1; i <= N; i++)da[i] = -1;

	sort(x, x + N);

	sort(y, y + N);

	list<long long int>edge[100001];

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

		int a = x[i] % MOD;

		int b = x[i + 1] % MOD;

		edge[a].push_back((x[i + 1] / MOD - x[i] / MOD)*MOD + b);

		edge[b].push_back((x[i + 1] / MOD - x[i] / MOD)*MOD + a);

		 a = y[i] % MOD;

		 b = y[i + 1] % MOD;

		edge[a].push_back((y[i + 1] / MOD - y[i] / MOD)*MOD + b);

		edge[b].push_back((y[i + 1] / MOD - y[i] / MOD)*MOD + a);

	}

	bool flag[100001] = {};

	flag[0] = true;

	int used = 1;

	priority_queue<long long int, vector<long long int>, greater<long long int>>Q;

	for (auto i : edge[0])Q.push(i);

	while (used<N) {

		long long int a = Q.top();

		Q.pop();

		if (flag[a%MOD])continue;

		used++;

		flag[a%MOD] = true;

		ans += a / MOD;

		for (auto i : edge[a%MOD])Q.push(i);

	}

	cout << ans << endl;

	return 0;

}

// Optimized solution to the same problem (faster):
#include "iostream"

#include "climits"

#include "list"

#include "queue"

#include "stack"

#include "set"

#include "functional"

#include "algorithm"

#include "string"

#include "map"

#include "unordered_map"

#include "unordered_set"

#include "iomanip"

#include "cmath"

#include "random"

#include "bitset"



using namespace std;



const long long int MOD = 1000000007;



long long int N, M, K, H, W, L, R;



class xplace {

public:

	int x;

	int y;

	int node;

	bool operator <(const xplace& xp)const {

		return x < xp.x;

	}

	bool operator >(const xplace& xp)const {

		return x > xp.x;

	}

};



class yplace {

public:

	int x;

	int y;

	int node;

	bool operator <(const yplace& yp)const {

		return y < yp.y;

	}

	bool operator >(const yplace& yp)const {

		return y > yp.y;

	}

};



class Edge {

public:

	int l;

	int r;

	int cost;

	bool operator <(const Edge& e)const {

		return cost < e.cost;

	}

	bool operator >(const Edge& e)const {

		return cost > e.cost;

	}

};



class UnionFind {

	vector<int>parent;

	vector<int>rank;

public:

	UnionFind(int num) {

		num++;

		parent.resize(num);

		rank.resize(num);

		for (int i = 0; i < num; i++) {

			parent[i] = i;

			rank[i] = 0;

		}

	}

	int Find(int node) {

		if (parent[node] == node)return node;

		else return parent[node] = Find(parent[node]);

	}

	void Unite(int u, int v) {

		u = Find(u);

		v = Find(v);

		if (u == v)return;

		if (rank[u] < rank[v])parent[u] = v;

		else {

			parent[v] = u;

			if (rank[u] == rank[v])rank[u]++;

		}

	}

	bool Check_Same(int u, int v) {

		return Find(u) == Find(v);

	}

};



int main() {

	ios::sync_with_stdio(false);

	cin.tie(0);



	cin >> N;

	vector<xplace>xp;

	vector<yplace>yp;

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

		cin >> L >> R;

		xplace x;

		x.node = i;

		x.x = L;

		x.y = R;

		yplace y;

		y.node = i;

		y.x = L;

		y.y = R;

		xp.push_back(x);

		yp.push_back(y);

	}

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

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

	vector<Edge>edge;

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

		Edge e;

		e.l = xp[i].node;

		e.r = xp[i + 1].node;

		e.cost = min(abs(xp[i].x - xp[i + 1].x), abs(xp[i].y - xp[i + 1].y));

		edge.push_back(e);

		e.l = yp[i].node;

		e.r = yp[i + 1].node;

		e.cost = min(abs(yp[i].x - yp[i + 1].x), abs(yp[i].y - yp[i + 1].y));

		edge.push_back(e);

	}

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

	UnionFind uf(N);

	long long int ans = 0;

	for (auto i : edge) {

		if (uf.Check_Same(i.l, i.r)) {

			continue;

		}

		uf.Unite(i.l, i.r);

		ans += i.cost;

	}

	cout << ans << endl;

	return 0;

}

// Fastest known solution for this problem: