// Slower C++ solution:
#include <bits/stdc++.h>



using namespace std;



const int N = 2e5 + 5;



struct point {

    int x, y, id;

} a[N];



bool cmp1(const point& a, const point& b) {

    if (a.x != b.x) {

        return a.x < b.x;

    }

    return a.y < b.y;

}



bool cmp2(const point& a, const point& b) {

    if (a.y != b.y) {

        return a.y < b.y;

    }

    return a.x < b.x;

}



int n;

bool visited[N];

vector<pair<long long, int> > g[N];



long long prim(int x) {

    priority_queue<pair<long long, int>, vector<pair<long long, int> >, greater<pair<long long, int> > > pq;

    long long ans = 0;

    pq.push({0, x});

    while(!pq.empty()) {

        pair<long long, int> p = pq.top();

        pq.pop();

        x = p.second;

        if (visited[x]) {

        	continue;

		}

        ans += p.first;

        visited[x] = true;

        for(int i = 0; i < g[x].size(); i++) {

            int y = g[x][i].second;

            if (!visited[y]) {

            	pq.push(g[x][i]);

            }

        }

    }

    return ans;

}



int main() {

	ios::sync_with_stdio(false);

	cin.tie(nullptr);

	cin >> n;

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

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

		a[i].id = i + 1;

	}

	sort(a, a + n, cmp1);

	for (int i = 1; i < n; i++) {

		g[a[i].id].push_back({abs(a[i].x - a[i - 1].x), a[i - 1].id});

		g[a[i - 1].id].push_back({abs(a[i].x - a[i - 1].x), a[i].id});

	}

	sort(a, a + n, cmp2);

	for (int i = 1; i < n; i++) {

		g[a[i].id].push_back({abs(a[i].y - a[i - 1].y), a[i - 1].id});

		g[a[i - 1].id].push_back({abs(a[i].y - a[i - 1].y), a[i].id});

	}

	cout << prim(1) << '\n';

	return 0;

}


// Faster C++ solution for the same problem (measured speedup: 6.504254812774373x):
#include <bits/stdc++.h>

using namespace std;

//#define cerr if (false) cerr

#define db(x) cerr << #x << "=" << x << endl

#define db2(x, y) cerr << #x << "=" << x << "," << #y << "=" << y << endl

#define db3(x, y, z) cerr << #x << "=" << x << "," << #y << "=" << y << "," << #z << "=" << z << endl

#define dbv(v) cerr << #v << "="; for (auto _x : v) cerr << _x << ", "; cerr << endl

#define dba(a, n) cerr << #a << "="; for (int _i = 0; _i < (n); ++_i) cerr << a[_i] << ", "; cerr << endl

template <typename A, typename B>

ostream& operator<<(ostream& os, const pair<A, B>& x) {

	return os << "(" << x.first << "," << x.second << ")";

}

typedef long long ll;

typedef long double ld;

int main() {

	int n;

	scanf("%d", &n);

	vector<int> X(n), Y(n), id(n);

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

		scanf("%d%d", &X[i], &Y[i]);

		id[i] = i;

	}

	vector<pair<int, pair<int, int>>> edges;

	sort(id.begin(), id.end(), [&](int a, int b) {

		return X[a] < X[b];

	});

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

		edges.push_back({min(abs(X[id[i]] - X[id[i + 1]]), abs(Y[id[i]] - Y[id[i + 1]])), {id[i], id[i + 1]}});

	}

	sort(id.begin(), id.end(), [&](int a, int b) {

		return Y[a] < Y[b];

	});

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

		edges.push_back({min(abs(X[id[i]] - X[id[i + 1]]), abs(Y[id[i]] - Y[id[i + 1]])), {id[i], id[i + 1]}});

	}

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

	vector<int> par(n);

	iota(par.begin(), par.end(), 0);

	function<int(int)> getRoot = [&](int a) {

		if (par[a] == a) return a;

		return par[a] = getRoot(par[a]);

	};

	ll ans = 0;

	for (int i = 0; i < edges.size(); ++i) {

		int a, b;

		tie(a, b) = edges[i].second;

		int pa = getRoot(a), pb = getRoot(b);

		if (pa == pb) continue;

		par[pa] = pb;

		ans += edges[i].first;

	}

	printf("%lld\n", ans);

}