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

using namespace std;



#define fi first

#define se second

const int inf = 1e9 + 7;

int n, par[100010], ans = 0;

pair <pair <int, int>, int> a[100010]; bool dis[100010];

priority_queue<pair <int, pair <int, int> >, vector<pair <int, pair <int, int> > >, greater<pair <int, pair <int, int> > > > wl1, wl2;

int find(int a) {

	return (par[a] < 0 ? a : par[a] = find(par[a]));

}

void unionset(int a, int b) {

	int c = find(a), d = find(b);

	if(par[c] < par[d]) par[c] += par[d], par[d] = c;

	else par[d] += par[c], par[c] = d;

}

int main() {

	memset(par, -1, sizeof(par));

	scanf("%d", &n);

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

		scanf("%d%d", &a[i].fi.fi, &a[i].fi.se);

		a[i].se = i;

	}

	sort(a, a + n);

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

		wl1.push({a[i+1].fi.fi - a[i].fi.fi, {a[i].se, a[i+1].se}});

		swap(a[i].fi.fi, a[i].fi.se);

	}

	swap(a[n-1].fi.fi, a[n-1].fi.se);

	sort(a, a + n);

	for(int i = 0; i < n-1; i++) wl2.push({a[i+1].fi.fi - a[i].fi.fi, {a[i].se, a[i+1].se}});

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

		while(find(wl1.top().se.fi) == find(wl1.top().se.se)) wl1.pop();

		while(find(wl2.top().se.fi) == find(wl2.top().se.se)) wl2.pop();

		int d1 = inf, d2 = inf, u1, u2, v1, v2;

		if(not wl1.empty()) d1 = wl1.top().fi, u1 = wl1.top().se.fi, v1 = wl1.top().se.se;

		if(not wl2.empty()) d2 = wl2.top().fi, u2 = wl2.top().se.fi, v2 = wl2.top().se.se;

		if(d1 < d2) {

			unionset(u1, v1);

			ans += d1;

		}

		else {

			unionset(u2, v2);

			ans += d2;

		}

	}

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

}

// Faster C++ solution for the same problem (measured speedup: 1.3715432265553216x):
#pragma GCC optimize ("O3")

#include <bits/stdc++.h>

using namespace std;

#define MuhammedAly ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0);

#define all(x) (x).begin(),(x).end()

#define allr(x) (x).rbegin(),(x).rend()

#define pb push_back

#define eb emplace_back

#define popc(x) __builtin_popcount(x)

#define LLMX 1e18

#define NotinRange(n,m) i<0||i>=(n)||j<0||j>=(m)

#define mem(x,y) memset((x),(y),sizeof (x));

#define sz(a) (int)(a).size()

#define inFile(s) freopen((s),"r",stdin)

#define	outFile(s) freopen((s),"w",stdout)

#define biEdge(v, a, b) (v)[(a)].pb((b)), (v)[(b)].pb((a))

#define pi (2 * acos(0))

#define X real()

#define Y imag()

#define cross(a, b) ((conj(a) * (b)).Y)

#define dot(a, b) ((conj(a) * (b)).X)

#define vec(a,b) ((b) - (a))

#define ll long long

typedef long double ld;

typedef complex<double>point;

typedef tuple<int, int, int> line;

typedef pair<point, point>segment;

typedef vector<point>polygon;

const int N = 1e5 + 5, M = 100 + 5, OO = 0x3f3f3f3f, mod = 1e9 + 7, base = 131, mod2 = 1000136437, mod3 = 998244353;

const double EPS = 1e-9;

int n, rp[N], si[N];

ll ans;

vector<pair<int, pair<int, int>>>x, y;

map<int, vector<pair<int, int>>> mp;

int find(int u)

{

	return (rp[u] == u)? u : rp[u] = find(rp[u]);

}

bool join(int u, int v)

{

	u = find(u), v = find(v);

	if(u == v)

		return false;

	if(si[u] < si[v])

		swap(u, v);

	si[u] += si[v];

	rp[v] = u;

	return true;

}

int main()

{

    MuhammedAly

    cin >> n;

    fill(si, si + n + 1, 1);

    iota(rp, rp + n + 1, 0);

    x.resize(n);

    y.resize(n);

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

    {

    	cin >> x[i].first >> x[i].second.first;

    	y[i].first = x[i].second.first;

    	y[i].second.first = x[i].first;

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

    }

    sort(all(x));

    sort(all(y));

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

    {

    	mp[x[i + 1].first - x[i].first].pb({x[i].second.second, x[i + 1].second.second});

    	mp[y[i + 1].first - y[i].first].pb({y[i].second.second, y[i + 1].second.second});

    }

    for(auto i : mp)

    {

    	for(auto j : i.second)

    		if(join(j.second, j.first))

    			ans += i.first;

    }

    cout << ans;

    return 0;

}