// Original C++ solution (slower):
/*input

1

1 5

*/

#include <iostream>

#include <cstdio>

#include <vector>

#include <functional>

#include <cmath>

#include <cstring>

#include <utility>

#include <algorithm>

#include <iomanip>

#include <stack>

#include <queue>

#include <set>

#include <map>

#include <bitset>

#include <list>

#include <cstdlib>

#include <list>

#include <cassert>

#include <ctime>

#include <fstream>

#include <sstream>

#define fi first

#define se second

#define endl '\n'

#define N 100005

#define INF 1000000000

#define mod 1000000007

#define oo 1000000000000000000

// #define int long long

using namespace std;

typedef pair<int,int> ii;

long long n,res = 0,u,v;

vector<ii> a,b;

// map<ii,bool> done;

vector<pair<int,ii> > adj;

vector<int> pset;

void init(int n){

	pset.assign(n+1,0);

	for(int i=1;i<=n;i++){

		pset[i] = i;

	}

}

int findset(int i){

	if(pset[i] == i) return i;

	return pset[i] = findset(pset[i]);

}

bool issameset(int i,int j){

	return findset(i) == findset(j);

}

void unionset(int i,int j){

	if(issameset(i,j)) return;

	pset[findset(j)] = findset(i);

}

signed main(){

	ios_base::sync_with_stdio(0);

	// freopen(".inp","r",stdin);

	// freopen(".out","w",stdout);

	cin >> n;

	init(n);

	for(int i=1;i<=n;i++){

		cin >> u >> v;

		a.push_back(ii(u,i));

		b.push_back(ii(v,i));

	}

	sort(a.begin(),a.end());

	sort(b.begin(),b.end());

	for(int i=1;i<n;i++){

		adj.push_back(make_pair(a[i].fi - a[i-1].fi,ii(a[i].se,a[i-1].se)));

		adj.push_back(make_pair(b[i].fi - b[i-1].fi,ii(b[i].se,b[i-1].se)));

	}

	sort(adj.begin(),adj.end());

	for(int i=0;i<adj.size();i++){

		u = adj[i].se.fi, v = adj[i].se.se;

		if(issameset(u,v)) continue;

		unionset(u,v);

		res += adj[i].fi;

	}

	cout << res << endl;

    return 0;

}

// Optimized solution to the same problem (faster):
#include <stdio.h>

#include <stdlib.h>

#include <algorithm>



// 全局变量

const int N = 100010 , M = N + N;

int x[N],y[N],id[N],n;



typedef struct ufset *UFset;

struct ufset

{

  int *parent;

  int *root;

};

UFset UFinit(int size)

{

  int e;

  UFset U=(UFset)malloc(sizeof *U);

  U->parent=(int*)malloc((size+1)*sizeof(int));

  U->root=(int*)malloc((size+1)*sizeof(int));

  for(e=1; e<=size; e++)

  {

    U->parent[e]=1;

    U->root[e]=1;

  }

  return U;

}

int UFfind(int e,UFset U)

{

  int i,j = e;

  while(!U->root[j]) j = U->parent[j];

  while(j!=e){

    i = U->parent[e];

    U->parent[e]=j;

    e=i;

  }

  return j;

}

int UFunion(int i,int j,UFset U)

{

  if(U->parent[i]<U->parent[j])

  {

    U->parent[j]+=U->parent[i];

    U->root[i]=0;

    U->parent[i]=j;

    return j;

  }

  else

  {

    U->parent[i]+=U->parent[j];

    U->root[j]=0;

    U->parent[j]=i;

    return i;

  }

}



// 记录优化后的边集数

struct Edge

{

  int u, v, cost;

  bool operator <(const Edge&b) const

  {

    return cost < b.cost;

  }

} edge[M];

int tot;

// 按照X轴排序

bool cmpX(int a, int b)

{

  return x[a] < x[b];

}

// 按照Y轴排序

bool cmpY(int a, int b)

{

  return y[a] < y[b];

}

void add(int c, int a, int b)

{

  edge[tot].cost = c;

  edge[tot].u = a;

  edge[tot++].v = b;

}

int main()

{

  scanf("%d", &n);

  int i;

  for (i = 1; i <= n; ++i)

  {

    scanf("%d%d", x + i, y + i);

    id[i] = i;

  }

  std::sort(id + 1 , id + n + 1, cmpX);

  for (i = 2; i <= n; ++i)

    add(x[id[i]] - x[id[i - 1]], id[i], id[i - 1]);

  std::sort(id + 1 , id + n + 1, cmpY);

  for (i = 2; i <= n; ++i)

    add(y[id[i]] - y[id[i - 1]], id[i], id[i - 1]);

  UFset UFS = UFinit(n);



  // 按照花费排序

  std::sort(edge, edge + tot);

  long long totcost = 0;

  for (i = 0; i < tot; ++i)

  {

    int u = edge[i].u, v = edge[i].v;

    u = UFfind(u,UFS), v = UFfind(v,UFS);

    if (u != v)

    {

      UFunion(u,v,UFS);

      totcost += edge[i].cost;

    }

  }

  printf("%lld\n", totcost);

  return 0;

}

// Fastest known solution for this problem: