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;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Codeforces
{
	internal class Template
	{
		private void Solve()
		{
			var n = cin.NextInt();
			var towns = new Town[n];
			var adj = new List<Tuple<int, int>>[n];
			for (var i = 0; i < n; i++)
			{
				towns[i] = new Town(cin.NextInt(), cin.NextInt(), i);
				adj[i] = new List<Tuple<int, int>>();
			}
			var xx = towns.OrderBy(x => x.X).ToList();
			for (var i = 0; i < xx.Count; i++)
			{
				if (i - 1 >= 0)
				{
					adj[xx[i].Idx].Add(Tuple.Create(xx[i - 1].Idx, xx[i].X - xx[i - 1].X));
				}
				if (i + 1 < xx.Count)
				{
					adj[xx[i].Idx].Add(Tuple.Create(xx[i + 1].Idx, xx[i + 1].X - xx[i].X));
				}
			}
			var yy = towns.OrderBy(x => x.Y).ToList();
			for (var i = 0; i < yy.Count; i++)
			{
				if (i - 1 >= 0)
				{
					adj[yy[i].Idx].Add(Tuple.Create(yy[i - 1].Idx, yy[i].Y - yy[i - 1].Y));
				}
				if (i + 1 < yy.Count)
				{
					adj[yy[i].Idx].Add(Tuple.Create(yy[i + 1].Idx, yy[i + 1].Y - yy[i].Y));
				}
			}

			var dsu = DisjointSetSimple.createSets(n);
			var queue = new PriorityQueue<int, Tuple<int, int>>();
			for (var i = 0; i < adj.Length; i++)
			{
				foreach (var item in adj[i])
				{
					queue.Enqueue(item.Item2, Tuple.Create(i, item.Item1));
				}
			}
			var cost = 0L;
			while (queue.Any())
			{
				var front = queue.Dequeue();
				var value = front.Value;
				var key = front.Key;
				if (DisjointSetSimple.root(dsu, value.Item1) != DisjointSetSimple.root(dsu, value.Item2))
				{
					DisjointSetSimple.unite(dsu, value.Item1, value.Item2);
					cost += key;
				}
			}
			Console.WriteLine(cost);
		}

		public class Town
		{
			public int X, Y, Idx;

			public Town(int x, int y, int idx)
			{
				X = x;
				Y = y;
				Idx = idx;
			}
		}

		public class DisjointSetSimple
		{
			public static int[] createSets(int size)
			{
				int[] p = new int[size];
				for (int i = 0; i < size; i++)
					p[i] = i;
				return p;
			}

			public static int root(int[] p, int x)
			{
				return x == p[x] ? x : (p[x] = root(p, p[x]));
			}

			public static void unite(int[] p, int a, int b)
			{
				a = root(p, a);
				b = root(p, b);
				if (a != b)
					p[a] = b;
			}
		}

		public class PriorityQueue<TPriority, TValue> : ICollection<KeyValuePair<TPriority, TValue>>
		{
			private readonly List<KeyValuePair<TPriority, TValue>> baseHeap;
			private readonly IComparer<TPriority> comparer;

			public PriorityQueue()
				: this(Comparer<TPriority>.Default)
			{
			}

			public PriorityQueue(int capacity)
				: this(capacity, Comparer<TPriority>.Default)
			{
			}

			public PriorityQueue(int capacity, IComparer<TPriority> comparer)
			{
				if (comparer == null)
					throw new ArgumentNullException();

				baseHeap = new List<KeyValuePair<TPriority, TValue>>(capacity);
				this.comparer = comparer;
			}

			public PriorityQueue(IComparer<TPriority> comparer)
			{
				if (comparer == null)
					throw new ArgumentNullException();

				baseHeap = new List<KeyValuePair<TPriority, TValue>>();
				this.comparer = comparer;
			}

			public PriorityQueue(IEnumerable<KeyValuePair<TPriority, TValue>> data)
				: this(data, Comparer<TPriority>.Default)
			{
			}

			public PriorityQueue(IEnumerable<KeyValuePair<TPriority, TValue>> data, IComparer<TPriority> comparer)
			{
				if (data == null || comparer == null)
					throw new ArgumentNullException();

				this.comparer = comparer;
				baseHeap = new List<KeyValuePair<TPriority, TValue>>(data);
				// heapify data
				for (int pos = baseHeap.Count / 2 - 1; pos >= 0; pos--)
					HeapifyFromBeginningToEnd(pos);
			}

			public static PriorityQueue<TPriority, TValue> MergeQueues(PriorityQueue<TPriority, TValue> pq1, PriorityQueue<TPriority, TValue> pq2)
			{
				if (pq1 == null || pq2 == null)
					throw new ArgumentNullException();
				// ReSharper disable once PossibleUnintendedReferenceComparison
				if (pq1.comparer != pq2.comparer)
					throw new InvalidOperationException("Priority queues to be merged must have equal comparers");
				return MergeQueues(pq1, pq2, pq1.comparer);
			}

			public static PriorityQueue<TPriority, TValue> MergeQueues(PriorityQueue<TPriority, TValue> pq1, PriorityQueue<TPriority, TValue> pq2, IComparer<TPriority> comparer)
			{
				if (pq1 == null || pq2 == null || comparer == null)
					throw new ArgumentNullException();
				// merge data
				PriorityQueue<TPriority, TValue> result = new PriorityQueue<TPriority, TValue>(pq1.Count + pq2.Count, pq1.comparer);
				result.baseHeap.AddRange(pq1.baseHeap);
				result.baseHeap.AddRange(pq2.baseHeap);
				// heapify data
				for (int pos = result.baseHeap.Count / 2 - 1; pos >= 0; pos--)
					result.HeapifyFromBeginningToEnd(pos);

				return result;
			}

			public void Enqueue(TPriority priority, TValue value)
			{
				Insert(priority, value);
			}

			public KeyValuePair<TPriority, TValue> Dequeue()
			{
				if (!IsEmpty)
				{
					KeyValuePair<TPriority, TValue> result = baseHeap[0];
					DeleteRoot();
					return result;
				}
				else
					throw new InvalidOperationException("Priority queue is empty");
			}

			public TValue DequeueValue()
			{
				return Dequeue().Value;
			}

			public KeyValuePair<TPriority, TValue> Peek()
			{
				if (!IsEmpty)
					return baseHeap[0];
				else
					throw new InvalidOperationException("Priority queue is empty");
			}

			public TValue PeekValue()
			{
				return Peek().Value;
			}

			public bool IsEmpty
			{
				get { return baseHeap.Count == 0; }
			}

			private void ExchangeElements(int pos1, int pos2)
			{
				KeyValuePair<TPriority, TValue> val = baseHeap[pos1];
				baseHeap[pos1] = baseHeap[pos2];
				baseHeap[pos2] = val;
			}

			private void Insert(TPriority priority, TValue value)
			{
				KeyValuePair<TPriority, TValue> val = new KeyValuePair<TPriority, TValue>(priority, value);
				baseHeap.Add(val);

				// heap[i] have children heap[2*i + 1] and heap[2*i + 2] and parent heap[(i-1)/ 2];

				// heapify after insert, from end to beginning
				HeapifyFromEndToBeginning(baseHeap.Count - 1);
			}


			private int HeapifyFromEndToBeginning(int pos)
			{
				if (pos >= baseHeap.Count) return -1;

				while (pos > 0)
				{
					int parentPos = (pos - 1) / 2;
					if (comparer.Compare(baseHeap[parentPos].Key, baseHeap[pos].Key) > 0)
					{
						ExchangeElements(parentPos, pos);
						pos = parentPos;
					}
					else break;
				}
				return pos;
			}


			private void DeleteRoot()
			{
				if (baseHeap.Count <= 1)
				{
					baseHeap.Clear();
					return;
				}

				baseHeap[0] = baseHeap[baseHeap.Count - 1];
				baseHeap.RemoveAt(baseHeap.Count - 1);

				// heapify
				HeapifyFromBeginningToEnd(0);
			}

			private void HeapifyFromBeginningToEnd(int pos)
			{
				if (pos >= baseHeap.Count) return;

				// heap[i] have children heap[2*i + 1] and heap[2*i + 2] and parent heap[(i-1)/ 2];

				while (true)
				{
					// on each iteration exchange element with its smallest child
					int smallest = pos;
					int left = 2 * pos + 1;
					int right = 2 * pos + 2;
					if (left < baseHeap.Count && comparer.Compare(baseHeap[smallest].Key, baseHeap[left].Key) > 0)
						smallest = left;
					if (right < baseHeap.Count && comparer.Compare(baseHeap[smallest].Key, baseHeap[right].Key) > 0)
						smallest = right;

					if (smallest != pos)
					{
						ExchangeElements(smallest, pos);
						pos = smallest;
					}
					else break;
				}
			}

			public void Add(KeyValuePair<TPriority, TValue> item)
			{
				Enqueue(item.Key, item.Value);
			}

			public void Clear()
			{
				baseHeap.Clear();
			}

			public bool Contains(KeyValuePair<TPriority, TValue> item)
			{
				return baseHeap.Contains(item);
			}

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

			public void CopyTo(KeyValuePair<TPriority, TValue>[] array, int arrayIndex)
			{
				baseHeap.CopyTo(array, arrayIndex);
			}

			public bool IsReadOnly
			{
				get { return false; }
			}

			public bool Remove(KeyValuePair<TPriority, TValue> item)
			{
				// find element in the collection and remove it
				int elementIdx = baseHeap.IndexOf(item);
				if (elementIdx < 0) return false;

				//remove element
				baseHeap[elementIdx] = baseHeap[baseHeap.Count - 1];
				baseHeap.RemoveAt(baseHeap.Count - 1);

				// heapify
				int newPos = HeapifyFromEndToBeginning(elementIdx);
				if (newPos == elementIdx)
					HeapifyFromBeginningToEnd(elementIdx);

				return true;
			}

			public IEnumerator<KeyValuePair<TPriority, TValue>> GetEnumerator()
			{
				return baseHeap.GetEnumerator();
			}

			IEnumerator IEnumerable.GetEnumerator()
			{
				return GetEnumerator();
			}
		}

		private static readonly Scanner cin = new Scanner();

		private static void Main()
		{
			new Template().Solve();
			Console.ReadLine();
		}
	}

	internal class Scanner
	{
		private string[] s = new string[0];
		private int i;
		private readonly char[] cs = { ' ' };

		public string NextString()
		{
			if (i < s.Length) return s[i++];
			var line = Console.ReadLine() ?? string.Empty;
			s = line.Split(cs, StringSplitOptions.RemoveEmptyEntries);
			i = 1;
			return s.First();
		}

		public double NextDouble()
		{
			return double.Parse(NextString());
		}

		public int NextInt()
		{
			return int.Parse(NextString());
		}

		public long NextLong()
		{
			return long.Parse(NextString());
		}
	}
}