#include <iostream>
#include <vector>
#include <map>
#include <set>
#include <unordered_set>
#include <stack>
#include <queue>
#include <math.h>
#include <string>
#include <numeric>
#include <algorithm>
#include <utility>

// 14:01



using std::cout;
using std::cin;
using namespace std;
typedef long long ll;
typedef unsigned long long ull;


ll fact(ll n, ll mod) {
    ll res = 1;
    while (n > 0) {
        res = (res * n) % mod;
        --n;
    }
    return res;
}

class DisjointSetUnion {
public:
    explicit DisjointSetUnion(uint32_t pointsCount);
    uint32_t find(uint32_t point);
    bool merge(uint32_t left, uint32_t right);
    uint32_t addPoint();
    uint32_t components() { return components_; }
private:
    std::vector<uint32_t> roots_;
    std::vector<uint32_t> size_;
    // use same stack for all calls of find method
    std::stack<uint32_t> nodes_;
    uint32_t components_;
};

DisjointSetUnion::DisjointSetUnion(uint32_t pointsCount) {
    roots_.resize(pointsCount);
    size_.assign(pointsCount, 1);
    components_ = pointsCount;
    for (uint32_t element = 0; element < pointsCount; ++element) {
        roots_[element] = element;
    }
}

uint32_t DisjointSetUnion::find(uint32_t point) {
    auto current = point;
    while (roots_[current] != current) {
        nodes_.push(current);
        current = roots_[current];
    }
    while (!nodes_.empty()) {
        roots_[nodes_.top()] = current;
        nodes_.pop();
    }
    return current;
}

bool DisjointSetUnion::merge(uint32_t left, uint32_t right) {
    left = find(left);
    right = find(right);
    if (left == right) {
        return false;
    }
    if (size_[left] < size_[right]) {
        std::swap(left, right);
    }
    roots_[right] = left;
    --components_;
    size_[left] += size_[right];
    return true;

}

uint32_t DisjointSetUnion::addPoint() {
    roots_.push_back(roots_.size());
    size_.push_back(1);
    ++components_;
    return roots_.size();
}

struct p {
    p(int a, int b, int c) : x(a), y(b), id(c) {};
    int x;
    int y;
    int id;
};

struct edge {
    edge(int a, int b, int c) : from(a), to(b), cost(c) {};
    int from;
    int to;
    int cost;

};
int main() {
    int task = 1;
//    cin >> task;
    while (task--) {
        int n;
        cin >> n;
        vector<p> points;
        for (int i = 0; i < n; ++i) {
            int x, y;
            cin >> x >> y;
            points.emplace_back(x, y, i);
        }
        sort(points.begin(), points.end(), [] (auto& l, auto& r) {
            return l.x < r.x;
        });
        vector<edge> edges;
        for (int i = 0; i + 1 < n; ++i) {
            edges.emplace_back(points[i].id, points[i + 1].id, points[i + 1].x - points[i].x);
        }
        sort(points.begin(), points.end(), [] (auto& l, auto& r) {
            return l.y < r.y;
        });
        for (int i = 0; i + 1 < n; ++i) {
            edges.emplace_back(points[i].id, points[i + 1].id, points[i + 1].y - points[i].y);
        }

        sort(edges.begin(), edges.end(), [] ( auto& l, auto& r) {
            return l.cost < r.cost;
        });


        DisjointSetUnion dsu(n);
        ll res = 0;
        for (auto& ed : edges) {
            if (dsu.merge(ed.from, ed.to)) {
                res += ed.cost;
            }
        }
        cout << res << "\n";
    }

    return 0;
}

Measured memory_bytes: 6132