#include <bits/stdc++.h>

#define REP(i, n) for(decltype(n) i = 0; i < n; i++)

#define ALL(c)   c.begin(), c.end()
#define SORT(c)  std::sort(ALL(c))
#define RSORT(c) std::sort(ALL(c), std::greater<decltype(c)::value_type>())

using namespace std;
using ll = long long;

const int MOD  = (int)1e9 + 7;
const int INF  = (int)1e9 + 1;
const ll  LINF = (ll)1e18 + 1;

class CommonGraph {
    using ll = long long;
public:
    struct Edge {
        enum class Type { Directed, Undirected };
        int    src, dst;
        ll     cost;
        Edge() = default;
        Edge(const int&    _src,
             const int&    _dst,
             const ll&     _cost = 0) :
            src(_src),
            dst(_dst),
            cost(_cost) { }
    };

    friend std::ostream& operator <<(std::ostream& os, const Edge& obj) {
        os << "src : "  << obj.src      << ", "
           << "dst : "  << obj.dst      << ", "
           << "cost : " << obj.cost;
        return os;
    }

    struct Vertex {
        ll cost;
        Vertex(const ll& _cost) : cost(_cost) { }
    };

    CommonGraph(const int& num_vertex,
                const Edge::Type& edge_type) :
        vertex_(num_vertex, 0),
        edge_(num_vertex),
        num_edge_(0),
        total_cost_(0),
        edge_type_(edge_type) { }

    ll getTotalCost() const {
        return total_cost_;
    }

    const std::vector<Vertex>& getVertex() const {
        return vertex_;
    }

    const std::vector<std::vector<Edge>>& getEdge() const {
        return edge_;
    }

    /**
     *  辺を追加する
     */
    void addEdge(const int& src,
                 const int& dst,
                 const ll&  cost) {
        switch(edge_type_) {
            case Edge::Type::Directed:
                edge_[src].emplace_back(src, dst, cost);
                break;
            case Edge::Type::Undirected:
                edge_[src].emplace_back(src, dst, cost);
                edge_[dst].emplace_back(dst, src, cost);
                break;
        }
        num_edge_++; total_cost_ += cost;
    }

    /**
     *  辺の情報を標準出力する
     */
    void dumpEdgeInfo() const {
        for(const auto& v : edge_) {
            for(const auto& e : v) {
                std::cout << "[" << e << "]" << std::endl;
            }
            std::cout << std::endl;
        }
    }

    /**
     *  DFSテンプレート
     *  例: 木における全ての頂点に対するある頂点からの最短距離
     */
    void dfs(const int& index,
             const ll&  inf_val = (ll)1e18 + 1) {
        std::fill(vertex_.begin(), vertex_.end(), inf_val);
        for(const auto& edge : edge_[index]) {
            if(vertex_[edge.dst].cost == inf_val) {
                vertex_[edge.dst].cost = vertex_[edge.src].cost + edge.cost;
                dfs(edge.dst);
            }
        }
    }

    /**
     *  全ての頂点に対してある頂点からの最短経路を求める(Bellman-Ford法)
     *  NOTE: 計算量O(|V||E|), 始点と非連結の頂点はLINFとする
     *  @start_index: 始点
     *  @Return: 解が求まればtrueを返す
     *           負の閉路が存在する場合falseを返す
     */
    bool calcMinCostByBellmanFord(const int& start_index,
                                  const ll&  inf_val = (ll)1e18 + 1) {
        std::fill(vertex_.begin(), vertex_.end(), inf_val);
        vertex_[start_index].cost = 0; size_t cnt = 0;
        while(true) {
            bool update = false;
            for(size_t i = 0; i < vertex_.size(); i++) {
                for(const auto& edge : edge_[i]) {
                    if(vertex_[edge.src].cost != inf_val) {
                        auto cost = vertex_[edge.src].cost + edge.cost;
                        if(cost < vertex_[edge.dst].cost) {
                            vertex_[edge.dst].cost = cost; update = true;
                        }
                    }
                }
            }
            if(!update) break;
            if(cnt == vertex_.size() - 1) return false;
            cnt++;
        }
        return true;
    }

    /**
     *  全ての頂点に対してある頂点からの最短経路を求める(dijkstra法)
     *  NOTE: 計算量O(|E|log|V|), 始点と非連結の頂点はLINFとする
     *  @start_index: 始点
     *  @Return: void
     */
    void calcMinCostByDijkstra(const int& start_index,
                               const ll&  inf_val = (ll)1e18 + 1) {
        using pll = std::pair<ll, ll>;
        std::fill(vertex_.begin(), vertex_.end(), inf_val);
        vertex_[start_index].cost = 0;
        std::priority_queue<pll, std::vector<pll>, std::greater<pll>> pq;
        pq.emplace(0, start_index);
        while(!pq.empty()) {
            auto top = pq.top(); pq.pop();
            if(vertex_[top.second].cost < top.first) continue;
            for(const auto& edge : edge_[top.second]) {
                auto cost = vertex_[top.second].cost + edge.cost;
                if(cost < vertex_[edge.dst].cost) {
                    vertex_[edge.dst].cost = cost;
                    pq.emplace(vertex_[edge.dst].cost, edge.dst);
                }
            }
        }
    }

    /**
     *  最小全域木を求める(Kruskal法)
     *  @Return: 最小全域木を返す
     *           グラフが非連結の場合、連結成分ごとに最小全域木を構成する
     */
    struct UF {
        struct N{ll p,r;N(const ll&_p=0,const ll&_r=0):p(_p),r(_r){}};std::vector<N>n;
        explicit UF(const ll&nn){n.reserve(nn);for(ll i=0;i<nn;i++){n.emplace_back(i);}}
        ll root(const ll&x){return(n[x].p==x)?x:n[x].p=root(n[x].p);}
        void unite(const ll&x,const ll&y){ll w=root(x);ll z=root(y);if(w!=z){if(n[w].r<n[z].r)std::swap(w,z);n[z].p=w;if(n[w].r==n[z].r)n[w].r++;}}
        bool same(const ll&x,const ll&y){return root(x)==root(y);}
    };
    CommonGraph generateMinimumSpanningTree() {
        if(edge_type_ != Edge::Type::Undirected) {
            throw std::logic_error("Graph type is invalid");
        }
        auto num_v = vertex_.size();
        CommonGraph mst(num_v, Edge::Type::Undirected);
        std::vector<Edge> mst_e;
        mst_e.reserve(num_edge_ * 2);
        for(const auto& v : edge_) for(const auto& e : v) mst_e.push_back(e);
        auto sort_rule = [](const Edge& l, const Edge& r) { return l.cost < r.cost; };
        sort(mst_e.begin(), mst_e.end(), sort_rule);
        UF uf(num_v);
        for(const auto& e : mst_e) {
            if(!uf.same(e.src, e.dst)) {
                mst.addEdge(e.src, e.dst, e.cost);
                uf.unite(e.src, e.dst);
            }
        }
        return mst;
    }

    /**
     *  全頂点間の最短距離を求める(Warshall-Floyd法)
     *  @Return: array[i][j] :: 頂点iから頂点jまでの最短距離
     */
    std::vector<std::vector<ll>> calcMinCostBetweenAllVertices() {
        std::vector<std::vector<ll>> dp(vertex_.size(),
                                        std::vector<ll>(vertex_.size(),
                                                        std::numeric_limits<uint>::max()));
        for(const auto& v : edge_) for(const auto& e : v) dp[e.src][e.dst] = e.cost;
        for(size_t i = 0; i < vertex_.size(); i++)
            for(size_t j = 0; j < vertex_.size(); j++)
                for(size_t k = 0; k < vertex_.size(); k++)
                    dp[j][k] = std::min(dp[j][k], dp[j][i] + dp[i][k]);
        return dp;
    }

private:
    std::vector<Vertex>            vertex_;
    std::vector<std::vector<Edge>> edge_;
    ll                             num_edge_;
    ll                             total_cost_;
    const Edge::Type               edge_type_;
};

int main() {
    try {
        cin.tie(0);
        ios::sync_with_stdio(false);

        int N;
        std::cin >> N;

        vector<pair<pair<int, int>, int>> city_prior_x;
        vector<pair<pair<int, int>, int>> city_prior_y;
        REP(i, N) {
            int x, y;
            std::cin >> x >> y;
            city_prior_x.emplace_back(make_pair(x, y), i);
            city_prior_y.emplace_back(make_pair(y, x), i);
        }

        CommonGraph g(N, CommonGraph::Edge::Type::Undirected);

        sort(ALL(city_prior_x));
        sort(ALL(city_prior_y));
        for(int i = 0; i < N - 1; i++) {
            g.addEdge(city_prior_x[i].second,
                      city_prior_x[i + 1].second,
                      min(abs(city_prior_x[i].first.first  - city_prior_x[i + 1].first.first),
                          abs(city_prior_x[i].first.second - city_prior_x[i + 1].first.second)));
            g.addEdge(city_prior_y[i].second,
                      city_prior_y[i + 1].second,
                      min(abs(city_prior_y[i].first.first  - city_prior_y[i + 1].first.first),
                          abs(city_prior_y[i].first.second - city_prior_y[i + 1].first.second)));
        }

        auto mst = g.generateMinimumSpanningTree();
        std::cout << mst.getTotalCost() << std::endl;
    }
    catch(const exception& e) {
        std::cout << e.what() << std::endl;
        exit(1);
    }
    return 0;
}


Measured memory_bytes: 30124