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

#define rep(i, n) for (int i = 0; i < (n); ++i)

#define sz(x) int(x.size())

using namespace std;

#define MAX_N (int)1e6



typedef long long ll;

const ll INF = 1LL << 60;

typedef pair<ll, ll> P;



int N, E;

vector<ll> x, y;



struct edge { ll u, v, cost; };

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

    return e1.cost < e2.cost;

}

// edge es[(int)1e6];

vector<edge> es;



class UnionFind {

    int par[MAX_N];  // 親

    int my_rank[MAX_N]; // 木の深さ



public:

    void init(int n) {

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

            par[i] = i;

            my_rank[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 (my_rank[x] < my_rank[y]) {

            par[x] = y;

        } else {

            par[y] = x;

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

        }

    }



    bool same(int x, int y) {

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

    }

};



ll kruskal() {

    // N 個

    UnionFind uf;

    uf.init(N);

    // sort(es, es + E, comp);

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

    ll res = 0;

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

        edge e = es[i];

        if (!uf.same(e.u, e.v)) {

            uf.unite(e.u, e.v);

            res += e.cost;

        }

    }



    return res;

}



int main() {

    cin >> N;

    x.resize(N);

    y.resize(N);

    rep(i, N) {

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

    }

    vector<P> x2;

    vector<P> y2;

    rep(i, N) {

        P px(x[i], i);

        x2.push_back(px);

        P py(y[i], i);

        y2.push_back(py);

    }

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

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



    // x の辺

    rep(i, N) {

        if (i - 1 >= 0) {

            edge ex = {x2[i].second, x2[i - 1].second, abs(x2[i].first - x2[i - 1].first)};

            es.push_back(ex);

        }

        if (i + 1 <= N - 1) {

            edge ex2 = {x2[i].second, x2[i + 1].second, abs(x2[i].first - x2[i + 1].first)};

            es.push_back(ex2);

        }

    }



    // y の辺

    rep(i, N) {

        if (i - 1 >= 0) {

            edge ey = {y2[i].second, y2[i - 1].second, abs(y2[i].first - y2[i - 1].first)};

            es.push_back(ey);

        }

        if (i + 1 <= N - 1) {

            edge ey2 = {y2[i].second, y2[i + 1].second, abs(y2[i].first - y2[i + 1].first)};

            es.push_back(ey2);

        }

    }

    E = es.size();

    ll ans = kruskal();

    cout << ans << endl;

}

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

#define rep(i, n) for (int i = 0; i < (n); ++i)

#define sz(x) int(x.size())

using namespace std;

typedef long long ll;

typedef pair<int, int> P;



const ll INF = 1LL << 60;

struct edge { ll cost, u, v; };



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

    return e1.cost < e2.cost;

}



class UnionFind {

public:

  //親の番号を格納する。親だった場合は-(その集合のサイズ)

  vector<int> Parent;



  //作るときはParentの値を全て-1にする

  //こうすると全てバラバラになる

  UnionFind(int N) {

    Parent = vector<int>(N, -1);

  }



  //Aがどのグループに属しているか調べる

  int root(int A) {

    if (Parent[A] < 0) return A;

    return Parent[A] = root(Parent[A]);

  }



  //自分のいるグループの頂点数を調べる

  int size(int A) {

    return -Parent[root(A)];//親をとってきたい]

  }



  //AとBをくっ付ける

  bool connect(int A, int B) {

    A = root(A);

    B = root(B);

    if (A == B) {

      return false;

    }



    if (size(A) < size(B)) swap(A, B);



    Parent[A] += Parent[B];



    Parent[B] = A;



    return true;

  }

};



ll N;

int main() {

    cin >> N;



    // edge es[100100];

    vector<edge> es;



    vector<P> a;

    vector<P> b;



    // 辺の数

    rep(i, N) {

        int x, y;

        cin >> x >> y;

        a.push_back(P(x, i));

        b.push_back(P(y, i));

    }

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

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



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

        P prev = a[i - 1];

        P current = a[i];



        ll w = abs(prev.first - current.first);

        edge e { w, prev.second, current.second };

        es.push_back(e);

    }



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

        P prev = b[i - 1];

        P current = b[i];



        ll w = abs(prev.first - current.first);

        edge e { w, prev.second, current.second };

        es.push_back(e);

    }



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

    UnionFind uf = UnionFind(N);



    ll cost = 0;

    rep(i, es.size()) {

        if (uf.root(es[i].u) != uf.root(es[i].v)) {

            uf.connect(es[i].u, es[i].v);

            cost += es[i].cost;

        }

    }

    cout << cost << endl;

}