Problem:
Score : 500 points

Problem Statement

There are N towns on a plane. The i-th town is located at the coordinates (x_i,y_i). There may be more than one town at the same coordinates.

You can build a road between two towns at coordinates (a,b) and (c,d) for a cost of min(|a-c|,|b-d|) yen (the currency of Japan). It is not possible to build other types of roads.

Your objective is to build roads so that it will be possible to travel between every pair of towns by traversing roads. At least how much money is necessary to achieve this?

Constraints

2 ≤ N ≤ 10^5

0 ≤ x_i,y_i ≤ 10^9

All input values are integers.

Input

Input is given from Standard Input in the following format:

N
x_1 y_1
x_2 y_2
:
x_N y_N

Output

Print the minimum necessary amount of money in order to build roads so that it will be possible to travel between every pair of towns by traversing roads.

Sample Input 1

3
1 5
3 9
7 8

Sample Output 1

3

Build a road between Towns 1 and 2, and another between Towns 2 and 3. The total cost is 2+1=3 yen.

Sample Input 2

6
8 3
4 9
12 19
18 1
13 5
7 6

Sample Output 2

8

Solution in C# (Mono 4.6.2.0) (judge verdict: Accepted)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ContestLibraryD065;

namespace ABC_D
{
    class D065
    {
        static void Main(string[] args)
        {
            int N = int.Parse(Console.ReadLine());
            List<Town> towns = new List<Town>();
            for(int i = 0; i < N; i++)
            {
                int[] a = Console.ReadLine().Split(' ').Select(z => int.Parse(z)).ToArray();
                Town t = new Town(i+1, a[0], a[1]);
                towns.Add(t);
            }

            List<Town> xtowns = towns.OrderBy(t => t.x).ToList();
            List<Town> ytowns = towns.OrderBy(t => t.y).ToList();

            Graph g = new Graph(N);


            for(int i = 1; i < N; i++)
            {
                Town t1 = xtowns[i - 1], t2 = xtowns[i];
                int distance = Math.Min(Math.Abs(t1.x - t2.x), Math.Abs(t1.y - t2.y));
                g.AddEdge(t1.id, t2.id, distance);
            }
            for (int i = 1; i < N; i++)
            {
                Town t1 = ytowns[i - 1], t2 = ytowns[i];
                int distance = Math.Min(Math.Abs(t1.x - t2.x), Math.Abs(t1.y - t2.y));
                g.AddEdge(t1.id, t2.id, distance);
            }

            double r = g.MinimumSpanningTree();
            Console.WriteLine(r);
        }

    }

    struct Town
    {
        public int id;
        public int x, y;


        public Town(int id,int x, int y)
        {
            this.id = id; this.x = x; this.y = y;
        }
    }
}

namespace ContestLibraryD065
{

    class Graph
    {
        public bool UseMatrix { get; set; }
        private bool idZeroStart;
        public List<Vertex> Vertices { get; }
        public List<Edge> Edges { get; }
        public double[,] Matrix { get; private set; }
        public bool IsDirectedGraph { get; }

        public Graph(int N, bool isDirectedGraph = false, bool idZeroStart = false, bool useMatrix = false)
        {
            IsDirectedGraph = isDirectedGraph;
            this.idZeroStart = idZeroStart;
            Vertices = new List<Vertex>();
            Edges = new List<Edge>();

            if (useMatrix) Matrix = new double[N, N];

            for (int i = 0; i < N; i++)
            {
                int id = idZeroStart ? i : i + 1;
                Vertex n = new Vertex(id);
                Vertices.Add(n);
            }
        }

        //隣接行列方式でのセットアップ
        public void SetAdjancencyMatrix(double[,] matrix)
        {
            Matrix = matrix;

            if (matrix.GetLength(0) != Vertices.Count || matrix.GetLength(1) != Vertices.Count)
            {
                throw new Exception("Invalid Matrix Size");
            }

            for (int i = 0; i < Vertices.Count; i++)
            {
                Vertex vertexL = Vertices[i];
                for (int j = 0; j < Vertices.Count; j++)
                {
                    if (i > j && !IsDirectedGraph) continue;
                    if (matrix[i, j] != double.PositiveInfinity)
                    {
                        Vertex vertexR = Vertices[j];
                        Edge edge = new Edge(vertexL, vertexR, matrix[i, j], IsDirectedGraph);
                        Edges.Add(edge);
                    }
                }
            }

        }


        //隣接リスト方式でのセットアップ
        public void AddAdjacencyList(int idVertex, Dictionary<int, double> adjDictionary)
        {
            int indexL = idZeroStart ? idVertex : idVertex - 1;
            Vertex vertexL = Vertices[indexL];

            foreach (var v in adjDictionary)
            {
                int idR = v.Key;
                double weight = v.Value;
                int indexR = idZeroStart ? idR : idR - 1;
                Vertex vertexR = Vertices[indexR];
                Edge edge = new Edge(vertexL, vertexR, weight, IsDirectedGraph);
                Edges.Add(edge);
                if (Matrix != null)
                {
                    Matrix[indexL, indexR] = weight;
                    if (!IsDirectedGraph) Matrix[indexR, indexL] = weight;
                }
            }
        }
        public void AddAdjacencyList(int idVertex, List<int> adjList)
        {
            Dictionary<int, double> dic = new Dictionary<int, double>();
            foreach (int x in adjList)
            {
                dic.Add(x, 1);
            }
            AddAdjacencyList(idVertex, dic);
        }

        //辺単位でのセットアップ
        public void AddEdge(int idL, int idR, int weight = 1)
        {
            int indexL = idZeroStart ? idL : idL - 1;
            int indexR = idZeroStart ? idR : idR - 1;

            Vertex vertexL = Vertices[indexL];
            Vertex vertexR = Vertices[indexR];
            Edge edge = new Edge(vertexL, vertexR, weight, IsDirectedGraph);
            Edges.Add(edge);
            if (Matrix != null)
            {
                Matrix[indexL, indexR] = weight;
                if (!IsDirectedGraph) Matrix[indexR, indexL] = weight;
            }
        }


        //開始点を指定し、幅優先探索で到達できる
        //頂点とステップ数（辺ウェイト考慮せず）のペアをDictionaryで出力
        public Dictionary<int, int> BreadthFirstSearch(int idS)
        {
            Dictionary<int, int> distances = new Dictionary<int, int>();
            distances.Add(idS, 0);
            int index = idZeroStart ? idS : idS - 1;

            List<Vertex> nodes = new List<Vertex>();
            Vertex nodeStart = Vertices[index];
            nodeStart.Visited = true;
            nodes.Add(nodeStart);
            int depth = 1;
            while (nodes.Count > 0)
            {
                List<Vertex> nextNodes = new List<Vertex>();
                foreach (Vertex node in nodes)
                {
                    foreach (Vertex cn in node.ConnectedVertices)
                    {
                        if (!cn.Visited)
                        {
                            nextNodes.Add(cn);
                            cn.Visited = true;
                            distances.Add(cn.Id, depth);
                        }
                    }
                }
                nodes = nextNodes;
                depth++;
            }
            return distances;
        }

        //開始点を指定し、深さ優先探索
        //TimeFound(訪問時刻)とTimeProcessed(処理完了時刻)を出力
        public int DepthFirstSearch(int idS, int connectGraphNo = 1, int time = 0)
        {
            Stack<Vertex> stack = new Stack<Vertex>();
            int index = idZeroStart ? idS : idS - 1;
            List<Vertex> nodes = new List<Vertex>();
            Vertex nodeStart = Vertices[index];
            nodeStart.Visited = true;

            stack.Push(nodeStart);
            nodeStart.TimeVisited = time;
            nodeStart.ConnectGraphNo = connectGraphNo;

            while (stack.Count > 0)
            {
                Vertex v = stack.Peek();

                if (v.IndexNextSearch >= v.ConnectedVertices.Count)
                {
                    time++;
                    v.TimeProcessed = time;
                    stack.Pop();
                }
                else
                {
                    Vertex vn = v.ConnectedVertices[v.IndexNextSearch];
                    if (!vn.Visited)
                    {
                        time++;
                        stack.Push(vn);
                        vn.Visited = true;
                        vn.TimeVisited = time;
                        vn.ConnectGraphNo = connectGraphNo;
                    }
                    v.IndexNextSearch++;
                }
            }
            return time;
        }

        //全頂点を探索
        public void DFS()
        {
            int time = 1;
            int connectNo = 1;
            int index = 0;
            while (index < Vertices.Count)
            {
                int id = idZeroStart ? index : index + 1;
                time = DepthFirstSearch(id, connectNo, time);

                while (index < Vertices.Count && Vertices[index].Visited) index++;
                connectNo++;
                time++;
            }
        }


        //Prim法で最小全域木を作成し重みの総和を計算(PriorityQueueクラスを利用)
        //辺に着目するためO(m log(m))であまり早くないが殆どの場合十分と思われる
        public double MinimumSpanningTree()
        {
            //最初に選ぶ頂点は何でもよい
            Vertex v0 = Vertices[0];

            bool[] includedVertex = new bool[Vertices.Count + 1];
            double sumWeight = 0;

            //最小全域木に含まれるEdge
            List<Edge> mstEdges = new List<Edge>();
            //現在の木に隣接しているEdgeの優先度付きキュー
            PriorityQueue<Edge> pq = new PriorityQueue<Edge>();

            includedVertex[v0.Id] = true;
            foreach (Edge en in v0.ConnectedEdges)
            {
                pq.Enqueue(en, -en.Weight);
            }

            int counter = 1;
            while (counter < Vertices.Count)
            {
                Edge edge = pq.Dequeue();
                Vertex v;
                //既に両方の頂点が木に含まれているEdgeは除外（含むとループができてしまう)
                if (includedVertex[edge.VertexL.Id] && includedVertex[edge.VertexR.Id]) continue;
                else if (includedVertex[edge.VertexL.Id]) v = edge.VertexR;
                else v = edge.VertexL;
                mstEdges.Add(edge);
                sumWeight += edge.Weight;
                includedVertex[v.Id] = true;

                //新しく木に隣接するようになったEdgeをキューに追加
                foreach (Edge e1 in v.ConnectedEdges)
                {
                    if (includedVertex[e1.VertexL.Id] && includedVertex[e1.VertexR.Id]) continue;
                    pq.Enqueue(e1, -e1.Weight);
                }

                counter++;
            }

            return sumWeight;
        }

        //O((|V|+|E|)ln(|V|)
        public double[] Dijkstra(int idS)
        {
            double[] distances = Enumerable.Repeat(double.PositiveInfinity, Vertices.Count + 1).ToArray();
            int index = idZeroStart ? idS : idS - 1;
            distances[idS] = 0;

            Vertex v0 = Vertices[index];

            PriorityQueue<Vertex> pq = new PriorityQueue<Vertex>();
            pq.Enqueue(v0, 0);

            while (pq.Count > 0)
            {
                Vertex v = pq.Dequeue();
                foreach (Edge e in v.ConnectedEdges)
                {
                    Vertex vn = e.VertexL == v ? e.VertexR : e.VertexL;
                    double distanceNew = distances[v.Id] + e.Weight;
                    if (distanceNew < distances[vn.Id])
                    {
                        distances[vn.Id] = distanceNew;
                        //distanceがより良い値に更新される時、
                        //同一のVertexが複数キューに入ることがあるが、
                        //先に入った（悪い方の）数値は必ず無視されるので問題ない
                        pq.Enqueue(vn, -distances[vn.Id]);
                    }
                }
            }


            return distances;
        }

        //負閉路を含む場合戻り値False
        //有向グラフ限定 重みマイナスを許容,ネガティブループ検出　O(|V||E|)
        public bool BellmanFord(int idS, out double[] distances)
        {
            distances = Enumerable.Repeat(double.PositiveInfinity, Vertices.Count + 1).ToArray();
            int index = idZeroStart ? idS : idS - 1;
            distances[idS] = 0;

            for (int i = 0; i < Vertices.Count - 1; i++)
            {
                foreach (Edge e in Edges)
                {
                    double dn = distances[e.VertexL.Id] + e.Weight;
                    if (dn < distances[e.VertexR.Id])
                    {
                        distances[e.VertexR.Id] = dn;
                    }
                }
            }

            foreach (Edge e in Edges)
            {
                if (distances[e.VertexR.Id] > distances[e.VertexL.Id] + e.Weight)
                {
                    return false;
                }
            }
            return true;
        }

        //全点対最短経路（ワ―シャル・フロイト） 要matrix
        public double[,] WarshallFloyd(out int[,] predecessorMatrix)
        {
            int N = Vertices.Count;
            double[,] d = (double[,])Matrix.Clone();

            int[,] p = new int[N, N]; //先行点行列
            for (int i = 0; i < N; i++)
            {
                for (int j = 0; j < N; j++)
                {
                    if (d[i, j] != double.PositiveInfinity && i != j)
                    {
                        p[i, j] = i; if (!idZeroStart) p[i, j]++;
                    }
                }
            }

            for (int k = 0; k < N; k++)
            {
                double[,] dn = new double[N, N];
                int[,] pn = new int[N, N];
                for (int i = 0; i < N; i++)
                {
                    for (int j = 0; j < N; j++)
                    {
                        if (i == j) continue;
                        //kを経由することで改善する場合
                        if (d[i, j] > d[i, k] + d[k, j])
                        {
                            dn[i, j] = d[i, k] + d[k, j];
                            pn[i, j] = p[k, j];
                        }
                        else
                        {
                            dn[i, j] = d[i, j];
                            pn[i, j] = p[i, j];
                        }
                    }
                }
                d = dn; p = pn;
            }
            predecessorMatrix = p;
            return d;
        }


    }

    class Vertex
    {
        public int Id { get; }
        public List<Edge> ConnectedEdges { get; private set; }
        public List<Vertex> ConnectedVertices { get; private set; }
        public bool Visited { get; set; }
        public int TimeVisited { get; set; }
        public int TimeProcessed { get; set; }
        public int IndexNextSearch { get; set; } //次に探索するVertex番号
        public int ConnectGraphNo { get; set; } //連結している頂点は同じ番号


        public Vertex(int id)
        {
            Id = id;
            ConnectedEdges = new List<Edge>();
            ConnectedVertices = new List<Vertex>();
        }


    }

    class Edge
    {
        public Vertex VertexL { get; }
        public Vertex VertexR { get; }
        public double Weight { get; }

        public Edge(Vertex vertexL, Vertex vertexR, double weight, bool isDirected)
        {
            VertexL = vertexL;
            VertexR = vertexR;
            vertexL.ConnectedEdges.Add(this);
            vertexL.ConnectedVertices.Add(vertexR);
            if (!isDirected)
            {
                vertexR.ConnectedEdges.Add(this);
                vertexR.ConnectedVertices.Add(vertexL);
            }
            Weight = weight;
        }
    }

    //優先度付きキュー（実装はヒープ)
    class PriorityQueue<T>
    {
        private List<HeapNode> heap = new List<HeapNode>();

        public int Count
        {
            get
            {
                return heap.Count;
            }
        }

        public void Enqueue(T item, double priority)
        {
            HeapNode node = new HeapNode(item, priority);
            heap.Add(node);

            int index = heap.Count - 1;

            while (index > 0)
            {
                int indexParent = (index - 1) / 2;
                HeapNode parent = heap[indexParent];
                if (priority > parent.Priority)
                {
                    Swap(index, indexParent);
                    index = indexParent;
                }
                else
                {
                    break;
                }
            }
        }

        public T Dequeue()
        {
            if (heap.Count == 0)
            {
                throw new Exception("No item in priorityQueue");
            }

            T item = heap[0].Node;
            heap[0] = heap[heap.Count - 1];
            heap.RemoveAt(heap.Count - 1);
            if (heap.Count > 0)
            {
                HeapNode node = heap[0];
                int index = 0;
                while (true)
                {
                    int indexL = 2 * index + 1;
                    int indexR = 2 * index + 2;
                    if (indexL >= heap.Count) //子なし(Leaf)
                    {
                        break;
                    }
                    else //子が存在
                    {
                        HeapNode childBetter = heap[indexL];
                        int indexBetter = indexL;
                        if (indexR < heap.Count && heap[indexL].Priority < heap[indexR].Priority)
                        {
                            childBetter = heap[indexR];
                            indexBetter = indexR;
                        }

                        if (node.Priority < childBetter.Priority)
                        {
                            Swap(index, indexBetter);
                            //node = childBetter; 参照なのでスワップで自動的に子を参照してる
                            index = indexBetter;
                        }
                        else
                        {
                            break;
                        }
                    }
                }
            }
            return item;
        }

        public T Peek()
        {
            if (heap.Count == 0)
            {
                throw new Exception("No item in priorityQueue");
            }
            return heap[0].Node;
        }

        private void Swap(int i, int j)
        {
            HeapNode hn = heap[i];
            heap[i] = heap[j];
            heap[j] = hn;
        }


        class HeapNode
        {
            public T Node { get; }
            public double Priority { get; }
            public HeapNode(T item, double priority)
            {
                Node = item;
                Priority = priority;
            }
        }

    }


}