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

class Program
{
	static int N;
	static long[][] coord;
	static long[][] xDist;
	static long[][] yDist;
	static long[][] distArr;
	static int[] unionFind;

	//camparer1
	static int CompareX(long[] a, long[] b)
  {
    long xa = a[0];
		long xb = b[0];

    if (xa > xb){
			return 1;
		}
    else if(xa < xb){
      return -1;
		}
    else{
			return 0;
		}
  }

	//camparer2
	static int CompareY(long[] a, long[] b)
	{
		long ya = a[1];
		long yb = b[1];

		if (ya > yb){
			return 1;
		}
		else if(ya < yb){
			return -1;
		}
		else{
			return 0;
		}
	}

	//unionFindへの追加
	//ここでは、a<bで渡されることを前提とする
	static void MergeUF(int a, int b){
		//根を決定
		int rootA = FindRoot(a);
		int rootB = FindRoot(b);
		int newRoot = Math.Min(rootA, rootB);

		//根を変化させる
		unionFind[rootA] = newRoot;
		unionFind[rootB] = newRoot;
	}

	static int FindRoot(int ind){
		int root = 0;

		if(unionFind[ind] == ind){
				root = ind;
		}else{
				root = FindRoot(unionFind[ind]);
		}

		return unionFind[ind] = root;
	}

	//Main
	static void Main(string[] args)
	{
		//読み込む
		N = int.Parse(Console.ReadLine());
		coord = new long[N][];

		for(long i=0; i<N; i++){
				string[] line = Console.ReadLine().Split(' ');
				//それぞれ、x座標、y座標、町の番号（インデックス）、を格納
				coord[i] = new long[3];
				coord[i][0] = long.Parse(line[0]);
				coord[i][1] = long.Parse(line[1]);
				coord[i][2] = (long)i;
		}

		//1. x座標の最小距離を格納した配列
		//まず、x座標でソート
		Array.Sort(coord, CompareX);

		//x座標の距離を取得し、配列に格納していく
		xDist = new long[N-1][];
		for(int i=0; i<N-1; i++){
				//距離
				long dist = coord[i+1][0] - coord[i][0];

				//町番号（小さい順）
				long minC = Math.Min(coord[i][2], coord[i+1][2]);
				long maxC = Math.Max(coord[i][2], coord[i+1][2]);

				//距離、町番号1、町番号2の順に格納
				xDist[i] = new long[3];
				xDist[i][0] = dist;
				xDist[i][1] = minC;
				xDist[i][2] = maxC;
		}

		//2. y座標の最小距離を格納した配列
		//まず、y座標でソート
		Array.Sort(coord, CompareY);

		//y座標の距離を取得し、配列に格納していく
		yDist = new long[N-1][];
		for(int i=0; i<N-1; i++){
				//距離
				long dist = coord[i+1][1] - coord[i][1];

				//町番号（小さい順）
				long minC = Math.Min(coord[i][2], coord[i+1][2]);
				long maxC = Math.Max(coord[i][2], coord[i+1][2]);

				//距離、町番号1、町番号2の順に格納
				yDist[i] = new long[3];
				yDist[i][0] = dist;
				yDist[i][1] = minC;
				yDist[i][2] = maxC;
		}

		//両者を結合
		distArr = new long[2*N-2][];
		for(int i=0; i<N-1; i++){
				distArr[i] = xDist[i];
		}
		for(int i=0; i<N-1; i++){
				distArr[i+N-1] = yDist[i];
		}

		//距離でソート
		Array.Sort(distArr, CompareX);

		/*
		ここまでで、重みの低い順に枝（頂点の組み合わせ）を並べ替えることは完了。
		後は、閉区間を弾ければ終了。
		（基本的に小さい順に重みを足していくが、
		同じ頂点同士を結んでいたり、或いは閉区間の場合には、スキップする必要）
		*/

		//unionFindの初期化
		unionFind = new int[N];
		for(int i=0; i<N; i++){
			unionFind[i] = i;
		}

		/*
		To do!!!
		UnionFindを理解し直し、新たな辺を付け加える際の根の更新関数を完成させよう！！
		（MergeUF関数）
		それができれば、後はwhileのループ処理内部を完成させるだけ。
		*/

		//最小全域木を結ぶ辺の数はN-1本である。
		long cnt = 0;
		long min = 0;
		int j = 0;

		while(cnt < N-1){
			//閉区間やダブリ（既に結ばれた辺）の場合（Union Find木で判定）
			//pa,pbはそれぞれ辺を結ぶ候補となっている2地点（pa < pb）
			int pa = (int)distArr[j][1];
			int pb = (int)distArr[j][2];
			unionFind[pa] = FindRoot(pa);
			unionFind[pb] = FindRoot(pb);

			/*デバッグ
			Console.Write(j + "| ");
			Console.Write(pa + ":" + unionFind[pa] + ",");
			Console.Write(pb + ":" + unionFind[pb] + " / ");
			*/

			//同じ根を持つ場合、飛ばして次へ
			if(unionFind[pa] == unionFind[pb]){
				j++;
				continue;
			}

			//その他の場合
			else{
				//最小値等の更新

				//Console.WriteLine(distArr[j][0]);

				min += distArr[j][0];
				cnt++;
				j++;

				//今回結ばれた辺を記憶（Union Find木を使う）
				MergeUF(pa, pb);
			}

		}

		/*デバッグ
		foreach(long[] co in coord){
				Console.WriteLine(co[0] + "," + co[1] + "," + co[2]);
		}
		foreach(long[] co in xDist){
				Console.WriteLine(co[0] + "," + co[1] + "," + co[2]);
		}
		foreach(long[] co in yDist){
				Console.WriteLine(co[0] + "," + co[1] + "," + co[2]);
		}
		*/

		/*デバッグ
		foreach(long[] co in distArr){
				Console.WriteLine(co[0] + "," + co[1] + "," + co[2]);
		}
		*/

		//出力
		Console.WriteLine(min);
	}
}