#include <iostream>
#include <algorithm>
#include <array>
#include <cstring>
#include <map>
#include <stack>
#include <set>
#include <tuple>
#include <queue>
#include <vector>
#include <cmath>
#include <random>
#include <math.h>
#include <random>



#define REP(i, n) for(int (i) = 0; (i) < (n); ++(i))
#define rREP(i, n) for(int (i) = (n) - 1; (i) >= 0; --(i))
#define ALL(TheArray) TheArray.begin(), TheArray.end()

using lli = long long int;
using pii = std::pair<int, int>;

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

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

template <class NumberType>
class Kruskal{
private:
    struct UnionFindTree{
    private:
        int m;
        std::vector<int> Parent;
        std::vector<int> SetSize;
    public:
        UnionFindTree(int mm = 0){
            m = mm;
            SetSize.resize(m, 0); Parent.resize(m);
            for(int v = 0; v < m; ++v) Parent[v] = v;
        }
        void resize(int mm){
            m = mm;
            SetSize.resize(m, 0); Parent.resize(m);
            for(int v = 0; v < m; ++v) Parent[v] = v;
        }
        int rootOf(int v){
            if(Parent[v] == v) return v;
            Parent[v] = rootOf(Parent[v]);
            return Parent[v];
        }
        // 頂点 x, y を併合する
        void unite(int x, int y){
            int root_x = rootOf(x);
            int root_y = rootOf(y);
            // 異なる集合に属する場合
            if(root_x == root_y) return;
            if(SetSize[root_x] < SetSize[root_y]) std::swap(root_x, root_y);
            Parent[root_y] = root_x;
            SetSize[root_x] += SetSize[root_y];
        }
        // 頂点 x, y が 同じ集合に属しているかを判定する
        bool sameSet(int x, int y){
            return rootOf(x) == rootOf(y);
        }
        // 頂点 x の属する集合の要素数
        int sizeOf(int x){
            return SetSize[rootOf(x)];
        }
    };
    using node = std::tuple<NumberType, int, int>;
    // コスト, 頂点1 頂点2

    const int n;
    std::vector<node> Node;
    UnionFindTree UFT;
public:
    std::vector<std::vector<std::pair<int, NumberType>>> TheTree;
    long long int ans;

    Kruskal(int nn): n(nn){
        UFT.resize(n); Node.resize(0); 
        TheTree.resize(n, std::vector<std::pair<int, NumberType>>(0));
    }
    void add(int a, int b, NumberType cost){
        Node.push_back({cost, a, b});
    }
    long long int compute(){
        ans = 0;
        std::sort(Node.begin(), Node.end(), std::greater<node>());
        while(not Node.empty()){
            int a, b; NumberType cost;
            std::tie(cost, a, b) = Node.back(); Node.pop_back();

            if(UFT.sameSet(a, b)) continue;

            UFT.unite(a, b);
            ans += cost;
            TheTree[a].push_back({b, cost});
            TheTree[b].push_back({a, cost});
        }
        return ans;
    }
};



using coordinate = std::pair<int, int>;
using myDatum = std::pair<coordinate, int>;
std::vector<myDatum> Vertices;

std::vector<std::vector<std::pair<int, int>>> E;


int main(void){
    int n; scanf("%d", &n);
    Vertices.resize(n);
    REP(i, n){
        auto& ptr = Vertices[i].first;
        scanf("%d%d", &ptr.first, &ptr.second);
        Vertices[i].second = i;
    }

    Kruskal<int> KSKL(n);

    std::sort(Vertices.begin(), Vertices.end());
    for(int x = 1; x < n; x++){
        int x0, x1, v0, v1;
        x0 = Vertices[x-1].first.first;
        x1 = Vertices[x].first.first;
        int cost = x1 - x0;
        v0 = Vertices[x-1].second;
        v1 = Vertices[x].second;
        KSKL.add(v0, v1, cost);
    }

    std::sort(Vertices.begin(), Vertices.end(), [](myDatum& a, myDatum& b){
        if(a.first.second != b.first.second) return a.first.second < b.first.second;
        if(a.first.first != b.first.first) return a.first.first < b.first.first;
        return a.second < b.second;
    });
    for(int y = 1; y < n; y++){
        int y0, y1, v0, v1;
        y0 = Vertices[y-1].first.second;
        y1 = Vertices[y].first.second;
        int cost = y1 - y0;
        v0 = Vertices[y-1].second;
        v1 = Vertices[y].second;
        KSKL.add(v0, v1, cost);
    }


    printf("%lld\n", KSKL.compute());

    return 0;
}

Measured memory_bytes: 11120