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

using namespace std;

const int N = 1e5 + 5;

int n, par[N], sz[N];

struct  poi{

    int x, y, idx;

}   p[N];

struct  edge    {

    int x, y, w;

}   e;

vector<edge>    E, MST;

int ans = 0;

bool cmp1(poi A,poi B)  {

    return A.x < B.x;

}

bool cmp2(poi A,poi B)  {

    return A.y < B.y;

}

bool cmp(edge e1,edge e2)   {

    return  e1.w < e2.w;

}

int findSet(int x)  {

    return  par[x] == x ? x : par[x] = findSet(par[x]);

}

void unionSet(int x,int y) {

    int a = findSet(x);

    int b = findSet(y);

    if(a == b)  return;

    if(sz[a] < sz[b])   swap(a,b);

    par[b] = a; sz[a] += sz[b];

}

int main()  {

    cin >> n;

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

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

        p[i].idx = i;

        par[i] = i;

        sz[i] = 1;

    }

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

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

        e.x = p[i].idx;

        e.y = p[i + 1].idx;

        e.w = p[i + 1].x - p[i].x;

        E.push_back(e);

    }

    sort(p + 1,p + 1 + n,cmp2);

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

        e.x = p[i].idx;

        e.y = p[i + 1].idx;

        e.w = p[i + 1].y - p[i].y;

        E.push_back(e);

    }

    sort(E.begin(),E.end(),cmp);

    int i = 0;

    while(MST.size() < n - 1)   {

        int x = E[i].x, y = E[i].y, W = E[i].w;

        ++i;

        if(findSet(x) == findSet(y))    continue;

        ans += W;   MST.push_back(E[i - 1]);

        unionSet(x,y);

    }

    cout << ans << endl;

}