#include <algorithm>
#include <functional>
#include <iostream>
#include <set>
#include <stack>
#include <string>
#include <utility>
#include <vector>

#define REP(i, n) for (int i = 0; i < n; i++)
#define ALL(obj) obj.begin(), obj.end()

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

const int iINF = 1e9;
const long long llINF = 1e18;
const int MOD = 1e9 + 7;

using namespace std;

template <int MOD>
struct Fp {
    long long val;
    constexpr Fp(long long v = 0) noexcept : val(v % MOD) {
        if (val < 0) val += MOD;
    }
    constexpr int getmod() { return MOD; }
    constexpr Fp operator-() const noexcept { return val ? MOD - val : 0; }
    constexpr Fp operator+(const Fp& r) const noexcept { return Fp(*this) += r; }
    constexpr Fp operator-(const Fp& r) const noexcept { return Fp(*this) -= r; }
    constexpr Fp operator*(const Fp& r) const noexcept { return Fp(*this) *= r; }
    constexpr Fp operator/(const Fp& r) const noexcept { return Fp(*this) /= r; }
    constexpr Fp& operator+=(const Fp& r) noexcept {
        val += r.val;
        if (val >= MOD) val -= MOD;
        return *this;
    }
    constexpr Fp& operator-=(const Fp& r) noexcept {
        val -= r.val;
        if (val < 0) val += MOD;
        return *this;
    }
    constexpr Fp& operator*=(const Fp& r) noexcept {
        val = val * r.val % MOD;
        return *this;
    }
    constexpr Fp& operator/=(const Fp& r) noexcept {
        long long a = r.val, b = MOD, u = 1, v = 0;
        while (b) {
            long long t = a / b;
            a -= t * b;
            swap(a, b);
            u -= t * v;
            swap(u, v);
        }
        val = val * u % MOD;
        if (val < 0) val += MOD;
        return *this;
    }
    constexpr bool operator==(const Fp& r) const noexcept { return this->val == r.val; }
    constexpr bool operator!=(const Fp& r) const noexcept { return this->val != r.val; }
    friend constexpr ostream& operator<<(ostream& os, const Fp<MOD>& x) noexcept { return os << x.val; }

    friend constexpr Fp<MOD> modpow(const Fp<MOD>& a, long long n) noexcept {
        if (n == 0) return 1;
        auto t = modpow(a, n / 2);
        t = t * t;
        if (n & 1) t = t * a;
        return t;
    }
};

using mint = Fp<MOD>;

struct Edge {
    int from, to;
    long long cost;
};

struct UnionFind {
    vector<int> par;

    UnionFind(int n) : par(n, -1) {}
    void init(int n) { par.assign(n, -1); }

    int root(int x) {
        if (par[x] < 0)
            return x;
        else
            return par[x] = root(par[x]);
    }

    bool is_same(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;
        par[x] += par[y];
        par[y] = x;
        return true;
    }

    int size(int x) { return -par[root(x)]; }
};

int main() {
    int N;
    cin >> N;
    vector<pair<long long, int>> x(N), y(N);
    REP(i, N) {
        cin >> x[i].first >> y[i].first;
        x[i].second = y[i].second = i;
    }
    vector<Edge> edges;
    sort(ALL(x));
    sort(ALL(y));
    auto comp = [](Edge a, Edge b) { return (a.cost < b.cost); };
    REP(i, N - 1) {
        edges.push_back(Edge{x[i].second, x[i + 1].second, abs(x[i].first - x[i + 1].first)});
        edges.push_back(Edge{y[i].second, y[i + 1].second, abs(y[i].first - y[i + 1].first)});
    }
    sort(ALL(edges), comp);
    UnionFind uf(N);
    long long ans = 0;
    for (auto e : edges) {
        if (uf.is_same(e.from, e.to)) continue;
        uf.merge(e.from, e.to);
        ans += e.cost;
    }
    cout << ans << endl;
    return 0;
}

Measured memory_bytes: 9328