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;
            }
        }

    }


}


Measured memory_bytes: 67180