// Original C++ solution (slower):
#include <bits/stdc++.h>

using namespace std;

typedef long long int ll;

#define MD 1000000007

#define INF 1ll<<60

typedef pair<ll, ll> P;

template <typename T>

std::string tostr(const T &t){std::ostringstream os;os << t;return os.str();}

int dx[4]={1, 0, -1, 0}, dy[4]={0, 1, 0, -1};



//親の場合parには，-(集合のサイズ)を格納

vector<ll> par(1e5+5,-1),dep(1e5+5,0);



//木の根を求める

ll find(ll x){

    if(par[x]<0){

        return x;

    }else{

        //return find(par[x])でも可能だが

        //根をつなぎなおして計算量を落としている

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

    }

}



//xとyが同じ集合に属するか否か

bool same(ll x, ll y){

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

}



//xとyの属する集合を併合

void unite(ll x, ll y){

    //同じ集合なら意味なし

    x=find(x);

    y=find(y);

    if(x==y) return;

    //rankの大小でどちらにくっつけるかを判定

    if(dep[x]<dep[y]){

        par[y]+=par[x];

        par[x]=y;

    }else{

        par[x]+=par[y];

        par[y]=x;

        //同じdepのときは，yをxにくっつけ

        //xのdepをプラスする

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

    }

}



//クラスカル法の準備

struct edge{

    int u,v,cost;

};



bool comp(const edge& e1, const edge& e2){

    return e1.cost<e2.cost;

}



int main(){

    int n;

    cin>>n;

    vector<pair<int,pair<int,int>>> pa_x(n),pa_y(n);

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

        int x,y;

        cin>>x>>y;

        pa_x[i]={x,{y,i}};

        pa_y[i]={y,{x,i}};

    }



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

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

    

    vector<edge> e;

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

        edge tmp={pa_x[i].second.second,pa_x[i+1].second.second,pa_x[i+1].first-pa_x[i].first};

        e.push_back(tmp);

        tmp={pa_x[i+1].second.second,pa_x[i].second.second,pa_x[i+1].first-pa_x[i].first};

        e.push_back(tmp);

    }

    

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

        edge tmp={pa_y[i].second.second,pa_y[i+1].second.second,pa_y[i+1].first-pa_y[i].first};

        e.push_back(tmp);

        tmp={pa_y[i+1].second.second,pa_y[i].second.second,pa_y[i+1].first-pa_y[i].first};

        e.push_back(tmp);

    }

    

    //クラスカル法

    sort(e.begin(),e.end(),comp);

    ll ans=0;

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

        edge tmp=e[i];

        if(!same(tmp.u,tmp.v)){

            unite(tmp.u,tmp.v);

            ans+=tmp.cost;

        }

    }

    cout<<ans<<endl;

    return 0;

}

// Optimized solution to the same problem (faster):
#include <bits/stdc++.h>

using namespace std;

typedef long long int ll;

#define MD 1000000007

#define INF 1ll<<60

typedef pair<ll, ll> P;

template <typename T>

std::string tostr(const T &t){std::ostringstream os;os << t;return os.str();}

int dx[4]={1, 0, -1, 0}, dy[4]={0, 1, 0, -1};



//親の場合parには，-(集合のサイズ)を格納

vector<int> par(1e5+5,-1),dep(1e5+5,0);



//木の根を求める

int find(int x){

    if(par[x]<0){

        return x;

    }else{

        //return find(par[x])でも可能だが

        //根をつなぎなおして計算量を落としている

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

    }

}



//xとyが同じ集合に属するか否か

bool same(int x, int y){

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

}



//xとyの属する集合を併合

void unite(int x, int y){

    //同じ集合なら意味なし

    x=find(x);

    y=find(y);

    if(x==y) return;

    //rankの大小でどちらにくっつけるかを判定

    if(dep[x]<dep[y]){

        par[y]+=par[x];

        par[x]=y;

    }else{

        par[x]+=par[y];

        par[y]=x;

        //同じdepのときは，yをxにくっつけ

        //xのdepをプラスする

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

    }

}



//クラスカル法の準備

struct edge{

    int u,v,cost;

};



bool comp(const edge& e1, const edge& e2){

    return e1.cost<e2.cost;

}



int main(){

    int n;

    cin>>n;

    vector<pair<int,pair<int,int>>> pa_x(n),pa_y(n);

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

        int x,y;

        cin>>x>>y;

        pa_x[i]={x,{y,i}};

        pa_y[i]={y,{x,i}};

    }



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

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

    

    vector<edge> e;

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

        edge tmp={pa_x[i].second.second,pa_x[i+1].second.second,pa_x[i+1].first-pa_x[i].first};

        e.push_back(tmp);

        tmp={pa_x[i+1].second.second,pa_x[i].second.second,pa_x[i+1].first-pa_x[i].first};

        e.push_back(tmp);

    }

    

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

        edge tmp={pa_y[i].second.second,pa_y[i+1].second.second,pa_y[i+1].first-pa_y[i].first};

        e.push_back(tmp);

        tmp={pa_y[i+1].second.second,pa_y[i].second.second,pa_y[i+1].first-pa_y[i].first};

        e.push_back(tmp);

    }

    

    //クラスカル法

    sort(e.begin(),e.end(),comp);

    int ans=0;

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

        edge tmp=e[i];

        if(!same(tmp.u,tmp.v)){

            unite(tmp.u,tmp.v);

            ans+=tmp.cost;

        }

    }

    cout<<ans<<endl;

    return 0;

}

// Fastest known solution for this problem: