#include <iostream>
#include <fstream>
#include <cstdio>
#include <cmath>
#include <vector>
#include <string>
#include <set>
#include <map>
#include <stack>
#include <queue>
#include <deque>
#include <bitset>
#include <algorithm>
#include <complex>
#include <array>
#include <iomanip>
using namespace std;

#define REP(i,n) for(int i=0; i<n; ++i)
#define FOR(i,a,b) for(int i=a; i<=b; ++i)
#define FORR(i,a,b) for (int i=a; i>=b; --i)
#define ALL(c) (c).begin(), (c).end()

typedef long long ll;
typedef vector<int> VI;
typedef vector<ll> VL;
typedef vector<long double> VD;
typedef vector<VI> VVI;
typedef vector<VL> VVL;
typedef vector<VD> VVD;
typedef pair<int,int> P;
typedef pair<ll,ll> PL;

template<typename T> void chmin(T &a, T b) { if (a > b) a = b; }
template<typename T> void chmax(T &a, T b) { if (a < b) a = b; }

int in() { int x; scanf("%d", &x); return x; }
ll lin() { ll x; scanf("%lld", &x); return x; }
#define INF 1LL<<60

struct edge {
    int from;
    int to;
    ll d;

    bool operator<(const edge& other) const {
        if (d < other.d) return true;
        else return false;
    }
};

class UnionFind {
public:
    int rank;
    vector <int> par; // 各元の親を表す配列
    vector <int> siz; // 素集合のサイズを表す配列(1 で初期化)

    // Constructor
    UnionFind(int sz_): par(sz_), siz(sz_, 1) {
        rank = sz_;
        for (int i = 0; i < sz_; ++i) par[i] = i; // 初期では親は自分自身
    }
    void init(int sz_) {
        rank = sz_;
        par.resize(sz_);
        siz.assign(sz_, 1);  // resize だとなぜか初期化されなかった
        for (int i = 0; i < sz_; ++i) par[i] = i; // 初期では親は自分自身
    }

    // Member Function
    // Find
    int root(int x) { // 根の検索
        while (par[x] != x) {
            x = par[x] = par[par[x]]; // x の親の親を x の親とする
        }
        return x;
    }

    // Union(Unite, Merge)
    bool merge(int x, int y) {
        x = root(x);
        y = root(y);
        if (x == y) return false;
        // merge technique（データ構造をマージするテク．小を大にくっつける）
        if (siz[x] < siz[y]) swap(x, y);
        siz[x] += siz[y];
        par[y] = x;
        rank--;
        return true;
    }

    bool issame(int x, int y) { // 連結判定
        return root(x) == root(y);
    }

    int size(int x) { // 素集合のサイズ
        return siz[root(x)];
    }
};

struct town_cord {
    int v;
    int idx;

    bool operator<(const town_cord& other) const {
        if (v < other.v) return true;
        else return false;
    }
};

int main() {
    int N;
    cin >> N;
    vector<P> towns;
    vector<town_cord> xs, ys;
    int n_unique_town = 0;

    UnionFind uf = UnionFind(N);
    vector<edge> edges;

    REP(i, N) {
        P town;
        cin >> town.first >> town.second;
        town_cord t1 = {town.first, i};
        town_cord t2 = {town.second, i};

        // auto xitr = xs.find(t1);
        // auto yitr = ys.find(t2);

        // if(xitr != xs.end()) {
        //     uf.merge(i, xitr->idx);
        //     ys.push_back(t2);
        // }
        // else if(yitr != ys.end()) {
        //     uf.merge(i, yitr->idx);
        //     xs.push_back(t1);
        // }
        // else {
        xs.push_back(t1);
        ys.push_back(t2);
        // }
    }

    // cerr << "prepare edge" << endl;

    // cerr << "xs.size() = " << xs.size() << endl;
    sort(ALL(xs));
    sort(ALL(ys));
    REP(i, xs.size() - 1) {
        town_cord x1 = xs[i];
        town_cord x2 = xs[i+1];
        if(!uf.issame(x1.idx, x2.idx)) {
            edge e = {x1.idx, x2.idx, abs(x1.v - x2.v)};
            edges.push_back(e);
        }
    }

    // cerr << "ys.size() = " << ys.size() << endl;
    REP(i, ys.size() - 1) {
        town_cord y1 = ys[i];
        town_cord y2 = ys[i+1];
        if(!uf.issame(y1.idx, y2.idx)) {
            edge e = {y1.idx, y2.idx, abs(y1.v - y2.v)};
            edges.push_back(e);
        }
    }

    // cerr << "get tree" << endl;
    sort(ALL(edges));
    vector<edge> tree;

    for(edge e: edges) {
        if(!uf.issame(e.from, e.to)) {
            uf.merge(e.from, e.to);
            tree.push_back(e);
        }
    }

    ll ans = 0;
    for(edge e: tree) {
        ans += e.d;
    }

    cout << ans << endl;

    return 0;
}


Measured memory_bytes: 12388