#include <algorithm>
#include <vector>
#include <unordered_map>
#include <unordered_set>
#include <queue>
#include <functional>
#include <climits>
#include <iostream>

namespace std {
    template <>
    class hash<std::pair<int, int>> {
    public:
        size_t operator()(const std::pair<int, int>& x) const {
            return hash<int>()(x.first) ^ hash<int>()(x.second);
        }
    };
}

class edge {
public:
    edge(int to, long long cost);
    int get_to() const;
    long long get_cost() const;
private:
    int to;
    long long cost;
};

edge::edge(int to, long long cost) : to(to), cost(cost) {}

int edge::get_to() const { return to; }

long long edge::get_cost() const { return cost; }

class prim
{
private:
    //unordered_mapを使って隣接リストを構築
    //first:接続元、second:辺のコストと接続先
    std::unordered_map<int, std::vector<edge>> adj_list;
    //最小全域木の隣接リスト
    std::unordered_map<int, std::vector<edge>> MST_list;
    int node_num;
    std::vector<bool> is_done;//確定ノードか否かを保持
    long long MST_cost;
public:
    prim(const int node_num, const std::unordered_map<int, std::vector<edge>>& adj_list);
    long long get_MST_cost() const;
    std::unordered_map<int, std::vector<edge>> calc_MST();
};

prim::prim(const int node_num, const std::unordered_map<int, std::vector<edge>>& adj_list):
    adj_list(adj_list),
    node_num(node_num),
    is_done(node_num + 1, false),
    MST_cost(0)
{

}

std::unordered_map<int, std::vector<edge>> prim::calc_MST() {
    MST_cost = 0;
    std::vector<long long> key(node_num + 1, LLONG_MAX);
    //優先度付きキューpairで頂点番号と最短距離を保持
    //firstの要素で比較されるので、firstが距離、secondをfrom,toのペアとする
    std::priority_queue<std::pair<long long, std::pair<int, int>>,
        std::vector<std::pair<long long, std::pair<int, int>>>, 
                        std::greater<std::pair<long long, std::pair<int, int>>>> p_queue;
    p_queue.push(std::make_pair(0,std::make_pair(-1, adj_list.begin()->first)));
    key[adj_list.begin()->first] = 0;
    while (1) {
        if (p_queue.empty() == true) break; //キューが空なら終了
        //std::cout << p_queue.size() << "\n";
        std::pair<long long, std::pair<int, int>> cost_node = p_queue.top();
        p_queue.pop();
        if (cost_node.second.first >= 0 && 
            is_done[cost_node.second.second] == false) {
            //最小全域木の隣接リストを構築
            MST_list[cost_node.second.first].
                push_back(edge(cost_node.second.second, cost_node.first));
            //無向グラフなので逆方向も
            MST_list[cost_node.second.second].
                push_back(edge(cost_node.second.first, cost_node.first));
            MST_cost += cost_node.first;
        }
        int from_node = cost_node.second.second;
        is_done[from_node] = true; //キューから取り出した頂点を確定頂点とする
        for (auto &it : adj_list[from_node]) {
            int adj_node = it.get_to();
            
            if (is_done[adj_node] == false) {
                long long adj_cost = it.get_cost();
                if (adj_cost < key[adj_node]) {
                    p_queue.push(std::make_pair(adj_cost,
                        std::make_pair(from_node, adj_node)));
                    key[adj_node] = adj_cost;
                }
            }
        }
    }
    return MST_list;
}


long long prim::get_MST_cost() const {
    return  MST_cost;
}

#define ATCODER

int main()
{
#ifndef ATCODER
    std::unordered_map<int, std::vector<edge>> adj_list;
    int N, M;
    std::cin >> N >> M;
    for (int i = 0; i < M; i++) {
        int a, b, c;
        std::cin >> a >> b >> c;
        adj_list[a].push_back(edge(b, c));
        adj_list[b].push_back(edge(a, c));
    }
    prim p(N, adj_list);
    p.calc_MST();
    return 0;
#else
    std::vector<std::pair<long long, int>> x_citys;
    std::vector<std::pair<long long, int>> y_citys;
    std::unordered_map<int, std::vector<edge>> adj_list;
    int N;
    std::cin >> N;
    for (int i = 0; i < N; i++) {
        int x, y;
        std::cin >> x >> y;
        x_citys.push_back(std::make_pair(x, i + 1));
        y_citys.push_back(std::make_pair(y, i + 1));
    }
    std::sort(x_citys.begin(), x_citys.end());
    std::sort(y_citys.begin(), y_citys.end()); 
    //std::unordered_map<std::pair<int, int>, long long> adj_map;
    //std::unordered_map<int, std::unordered_set<int>> adj_map;
    std::vector<std::pair<int, int>> adj_pair_list;
    for (int i = 0; i < N - 1; i++) {
        ///*
        //long long dist = abs(x_citys[i + 1].first - x_citys[i].first);
        //if (dist < adj_mat[x_citys[i].second][x_citys[i + 1].second]) {
        //    adj_mat[x_citys[i].second][x_citys[i + 1].second] = dist;
        //    adj_mat[x_citys[i + 1].second][x_citys[i].second] = dist;
        //    adj_map[x_citys[i].second].insert(x_citys[i + 1].second);
        //    adj_map[x_citys[i + 1].second].insert(x_citys[i].second);
        //}
        //dist = abs(y_citys[i + 1].first - y_citys[i].first);
        //if (dist < adj_mat[y_citys[i].second][y_citys[i + 1].second]) {
        //    adj_mat[y_citys[i].second][y_citys[i + 1].second] = dist;
        //    adj_mat[y_citys[i + 1].second][y_citys[i].second] = dist;
        //    adj_map[y_citys[i].second].insert(y_citys[i + 1].second);
        //    adj_map[y_citys[i + 1].second].insert(y_citys[i].second);
        //}
        //*/
        //std::pair<int, int> adj_pair1(x_citys[i].second, x_citys[i + 1].second);
        //std::pair<int, int> adj_pair2(x_citys[i + 1].second, x_citys[i].second);
        //long long dist = abs(x_citys[i + 1].first - x_citys[i].first);
        //if (adj_map.count(adj_pair1) == 0) {
        //    adj_map[adj_pair1] = dist;
        //    adj_map[adj_pair2] = dist;
        //}
        //else {
        //    if (dist < adj_map[adj_pair1]) {
        //        adj_map[adj_pair1] = dist;
        //        adj_map[adj_pair2] = dist;
        //    }
        //}

        //adj_pair1 = std::make_pair(y_citys[i].second, y_citys[i + 1].second);
        //adj_pair2 = std::make_pair(y_citys[i + 1].second, y_citys[i].second);
        //dist = abs(y_citys[i + 1].first - y_citys[i].first);
        //if (adj_map.count(adj_pair1) == 0) {
        //    adj_map[adj_pair1] = dist;
        //    adj_map[adj_pair2] = dist;
        //}
        //else {
        //    if (dist < adj_map[adj_pair1]) {
        //        adj_map[adj_pair1] = dist;
        //        adj_map[adj_pair2] = dist;
        //    }
        //}
        
       
        adj_list[x_citys[i].second].push_back(edge(x_citys[i + 1].second,
            abs(x_citys[i + 1].first - x_citys[i].first)));
        adj_list[x_citys[i + 1].second].push_back(edge(x_citys[i].second,
            abs(x_citys[i + 1].first - x_citys[i].first)));
        adj_list[y_citys[i].second].push_back(edge(y_citys[i + 1].second,
            abs(y_citys[i + 1].first - y_citys[i].first)));
        adj_list[y_citys[i + 1].second].push_back(edge(y_citys[i].second,
            abs(y_citys[i + 1].first - y_citys[i].first)));
       
    }

    //for (auto &it : adj_map) {
    //    adj_list[it.first.first].push_back(edge(it.first.second, it.second));
    //    //adj_list[it.first.second].push_back(edge(it.first.first, it.second));
    //}

    //for (auto &it1 : adj_map) {
    //    for (auto &it2 : it1.second) {
    //        adj_list[it1.first].push_back(edge(it2, adj_mat[it1.first][it2]));
    //    }
    //}

    prim p(N, adj_list);
    p.calc_MST();
    std::cout << p.get_MST_cost() << "\n";
    return 0;
#endif

}

Measured memory_bytes: 53348