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

#include <ext/pb_ds/assoc_container.hpp>

#include <ext/pb_ds/tree_policy.hpp>



using namespace std;

using namespace __gnu_pbds;



#define fi first

#define se second

#define mp make_pair

#define pb push_back

#define fbo find_by_order

#define ook order_of_key



typedef long long ll;

typedef pair<ll,ll> ii;

typedef vector<int> vi;

typedef long double ld;

typedef tree<int, null_type, less<int>, rb_tree_tag, tree_order_statistics_node_update> pbds;

bool marked[100001];

vector<ii> v[100001];  //adjList



ll prim(int k){

    priority_queue<ii, vector<ii>, greater<ii> > q;

    ll u;

    long long minimumCost = 0;

    ii p;

    q.push(mp(0, k));

    while(!q.empty())

    {

        p = q.top();

        q.pop();

        k = p.second;

        if(marked[k] == true)

            continue;

        minimumCost += p.fi;

        marked[k] = true;

        for(ll i = 0;i < v[k].size();++i)

        {

            u = v[k][i].se;

            if(marked[u] == false)

                q.push(v[k][i]);

        }

    }

    return minimumCost;

}



int main() {

    std::ios::sync_with_stdio(false);

    cin.tie(NULL);

    long long n;

    cin>>n;

    vector<ii> x;

    vector<ii> y;

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

        ll a,b;

        cin>>a>>b;

        x.pb(mp(a,i));

        y.pb(mp(b,i));

    }

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

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

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

        v[x[i].se].pb(mp(x[i+1].fi-x[i].fi,x[i+1].se));

        v[x[i+1].se].pb(mp(x[i+1].fi-x[i].fi,x[i].se));

        v[y[i].se].pb(mp(y[i+1].fi-y[i].fi,y[i+1].se));

        v[y[i+1].se].pb(mp(y[i+1].fi-y[i].fi,y[i].se));

    }

    ll ans=prim(0);

    cout<<ans;

    return 0;

}


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

using namespace std;



const int mx=1e6+5;



typedef long long ll;

typedef pair<ll,ll> ii;

typedef pair<ii,ll> iii;



int par[mx], rnk[mx];



void init(int n) {

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

		par[i]=i, rnk[i]=0;

}



int find(int x) {

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

	else return par[x]=find(par[x]);

}



void unite(int x, int y) {

	x=find(x);

	y=find(y);

	if(x==y) return;

	if(rnk[x]<rnk[y]) par[x]=y;

	else {

		par[y]=x;

		if(rnk[x]==rnk[y]) rnk[x]++;

	}

}



bool same(int x, int y) {

	return find(x)==find(y);

}



int main() {

	cin.tie(0); cout.tie(0); ios_base::sync_with_stdio(0);

	int N; cin>>N;

	vector<iii> v(N);

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

		int x,y; cin>>x>>y;

		v[i]={{x,y},i+1};

	}

	vector<iii> edges;

	sort(v.begin(),v.end(),[&](const iii &a, const iii &b) {

		return a.first.first<b.first.first;

	});

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

		int x=v[i].second, y=v[i-1].second, w=v[i].first.first-v[i-1].first.first;

		edges.push_back({{x,y},w});

	}

	sort(v.begin(),v.end(),[&](const iii &a, const iii &b) {

		return a.first.second<b.first.second;

	});

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

		int x=v[i].second, y=v[i-1].second, w=v[i].first.second-v[i-1].first.second;

		edges.push_back({{x,y},w});

	}

	sort(edges.begin(),edges.end(),[&](const iii &a, const iii &b) {

		return a.second<b.second;

	});

	init(N+1);

	ll ret=0;

	for (auto e : edges) {

		int x=e.first.first, y=e.first.second, w=e.second;

		if(same(x,y)) continue;

		unite(x,y);

		ret+=w;

	}

	cout<<ret<<"\n";

	return 0;

}