// 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.5041541460718846x):
#include<bits/stdc++.h>



using namespace std;



#define fi first

#define se second

#define pb push_back

#define mp make_pair



typedef pair<long long,long long> ii;

vector<pair<long long,ii>> edge;

long long n,up[100005],sz[100005];

pair<ii,long long> x[100005];



bool cmp(const pair<ii,long long> &a,const pair<ii,long long> &b){

    return a.fi.fi<b.fi.fi;

}

bool cmp1(const pair<ii,long long> &a,const pair<ii,long long> &b){

    return a.fi.se<b.fi.se;

}

int findSet(int x){

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

    else return findSet(up[x]);

}

void unionSet(int x,int y){

    long long x1=findSet(x),y1=findSet(y);

    if(sz[x1]<sz[y1]) swap(x1,y1);

    up[y1]=x1;

    sz[x1]+=sz[y1];

}

bool checkSet(int x,int y){

    long long x1=findSet(x),x2=findSet(y);

    if(x1==x2)

        return 1;

    else

        return 0;

}

int main(){

    cin.tie(0),cout.tie(0),ios::sync_with_stdio(0);

    cin>>n;

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

        cin>>x[i].fi.fi>>x[i].fi.se;

        x[i].se=i;

    }

    sort(x+1,x+1+n,cmp);

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

        up[i]=i;

        sz[i]=1;

    }

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

        long long x1=x[i].se,x2=x[i+1].se;

        long long val=abs(x[i].fi.fi-x[i+1].fi.fi),val1=abs(x[i].fi.se-x[i+1].fi.se);

        edge.pb(mp(min(val,val1),mp(x1,x2)));

    }

    sort(x+1,x+1+n,cmp1);

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

        long long x1=x[i].se,x2=x[i+1].se;

        long long val=abs(x[i].fi.fi-x[i+1].fi.fi),val1=abs(x[i].fi.se-x[i+1].fi.se);

        edge.pb(mp(min(val,val1),mp(x1,x2)));

    }

    long long sum=0;

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

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

        long long x1=edge[i].se.fi,x2=edge[i].se.se;

        if(checkSet(x1,x2)==0){

            unionSet(x1,x2);

            sum+=edge[i].fi;

        }

    }

    cout<<sum;

}