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

using namespace std;

#define FOR(i,l,r) for(long long i=(l);i<(r);++i)

#define REP(i,n) FOR(i,0,n)

#define REPS(i,n) FOR(i,0,n+1)

#define int long long

#define mp make_pair

#define pb push_back

#define eb emplace_back

const int MOD=1e9+7;

const int INF=1e18;

const int MAX_N=1e5;



struct Edge{

    int cost,to;

    Edge(int cost,int to):cost(cost),to(to){}

    bool operator<(const Edge& a) const{

        return cost >a.cost;

    }

};

using Graph=vector<Edge>;

Graph G[MAX_N];

int N;

bool used[MAX_N];

int res=0;



int prim(){

    REP(i,N)used[i]=false;

    used[0]=true;

    priority_queue<Edge>q;

    for(auto v:G[0]){

        q.push(v);

    }

    while(q.size()){

        Edge d=q.top();q.pop();

        if(used[d.to])continue;

        res+=d.cost;

      	used[d.to]=true;

        for(auto v:G[d.to]){

            if(!used[v.to])q.push(v);

        }

    }

    return res;

}



signed main(){

    cin>>N;

    vector<pair<int,int>>xdist(N);

    vector<pair<int,int>>ydist(N);

    REP(i,N){

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

        xdist[i]=mp(x,i);

        ydist[i]=mp(y,i);

    }

    sort(xdist.rbegin(),xdist.rend());

    sort(ydist.rbegin(),ydist.rend());

    REP(i,N-1){

        int m=xdist[i].second;

        int n=xdist[i+1].second;

        int cost=xdist[i].first-xdist[i+1].first;

        Edge e={cost,n};

        G[m].eb(e);

        e={cost,m};

        G[n].eb(e);

        m=ydist[i].second;

        n=ydist[i+1].second;

        cost=ydist[i].first-ydist[i+1].first;

        e={cost,n};

        G[m].eb(e);

        e={cost,m};

        G[n].eb(e);

    }

    cout<<prim()<<endl;

}

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

using namespace std;

#define ll long long

#define FOR(i,l,r) for(ll i=(l);i<(r);++i)

#define REP(i,n) FOR(i,0,n)

#define REPS(i,n) FOR(i,1,n+1)

#define RFOR(i,l,r) for(ll i=(l);i>=(r);--i)

#define RREP(i,n) RFOR(i,n-1,0)

#define RREPS(i,n) RFOR(i,n,1)

#define pb push_back

#define eb emplace_back

#define SZ(x) ((ll)(x).size())

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

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

template<class T = ll> using V = vector<T>;

template<class T = ll> using VV = V<V<T>>;

template<class T> inline bool chmin(T& a, T b) {if (a > b) {a = b; return true; }return false; }

template<class T> inline bool chmax(T& a, T b) {if (a < b) {a = b; return true; }return false; }

inline void Yes(bool b = true) {cout << (b ? "Yes" : "No") << '\n';}

inline void YES(bool b = true) {cout << (b ? "YES" : "NO") << '\n';}

inline void err(bool b = true) {if(b) {cout << -1 << '\n'; exit(0);}}

template<class T> inline void fin(bool b = true, T e = 0) {if(b) {cout << e << '\n'; exit(0);}}

template<class T> T Roundup_div(T x, T y) {return (x+(y-1))/y;}

const ll INF = 1e18;

template <typename T>

T pow(T a, long long n, T e = 1) {

    T ret = e;

    while (n) {

        if (n & 1) ret *= a;

        a *= a;

        n >>= 1;

    }

    return ret;

}



struct UnionFind {

    public:

    vector<int> par;

    UnionFind(int n){

        par=vector<int>(n,-1);

    }

    int root(int x){

        if(par[x]<0)return x;

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

    }

    bool issame(int x,int y){

        return root(x)==root(y);

    }

    bool merge(int x,int y){

        x=root(x);

        y=root(y);

        if(x==y)return false;

        if(par[x]>par[y])swap(x,y);

        par[x]+=par[y];

        par[y]=x;

        return true;

    }

    int size(int x){

        return -par[root(x)];

    }

};



struct Edge{

    ll from, to, cost;

    Edge(ll from, ll to,ll cost):from(from), to(to), cost(cost){}

    bool operator < (const Edge& a) const{

        return cost < a.cost;

    }

};

using Edges = vector<Edge>;

Edges E;

 

ll kruscal(ll n, Edges E){

    ll res = 0;

    sort(all(E));

    UnionFind uf(n);

    for(auto v:E) if(uf.merge(v.from, v.to)) res += v.cost; 

    return res;

}



using P = pair<ll, ll>;



int main(){

    ios::sync_with_stdio(false);

    cin.tie(nullptr);

    int n; cin >> n;

    V<P> xv(n), yv(n);

    REP(i, n){

        ll x, y; cin >> x >> y;

        xv[i] = {x, i};

        yv[i] = {y, i};

    }

    sort(rall(xv));

    sort(rall(yv));

    REP(i, n-1){

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

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

    }

    cout << kruscal(n, E) << '\n';

}