// Slower C++ solution:
#include<bits/stdc++.h>

#define lowbit(i) ((i)&(-i))

#define lson(i) ((i)<<1)

#define rson(i) ((i)<<1|1)

#define ft first

#define se second

#define MAXN 100007

using namespace std;



typedef long long ll;typedef unsigned long long ul;

typedef pair<int,int> pii;typedef pair<ll,ll> pll;

typedef vector<string> vss;

typedef vector<int> vii;typedef vector<pii> vpi;

typedef queue<int> qii;typedef queue<pii> qpi;



const int inf=2e9+7;



struct edge{

	ll x,y,val;

	edge(int _x,int _y,int _val){x=_x,y=_y,val=_val;}

};



vector<edge> v;



struct node{

	int x,y,num;

}dot1[MAXN],dot2[MAXN];



bool cmp1(node x,node y){

	return x.x<y.x;

}



bool cmp2(node x,node y){

	return x.y<y.y;

}



bool comp(edge x,edge y){

	return x.val<y.val;

}



int n,fa[MAXN];

ll res;



int find(int x){

	if(fa[x]==x) return x;

	return fa[x]=find(fa[x]);

}



void merge(int x,int y){

	int fx=find(x),fy=find(y);

	if(fx!=fy)

		fa[fx]=y;

}



int main()

{

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

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

	scanf("%d",&n);

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

		scanf("%d%d",&dot1[i].x,&dot1[i].y);

		dot2[i].x=dot1[i].x;dot2[i].y=dot1[i].y;

		dot2[i].num=dot1[i].num=i;

	}

	

	//建边(删除无用边) 

	sort(dot1+1,dot1+n+1,cmp1);

	sort(dot2+1,dot2+n+1,cmp2);

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

//		printf("num %d:(%d,%d)\n",i,dot1[i].x,dot1[i].y);

//	}

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

		v.push_back( edge(dot1[i-1].num,dot1[i].num,dot1[i].x-dot1[i-1].x) );

		v.push_back( edge(dot2[i-1].num,dot2[i].num,dot2[i].y-dot2[i-1].y) );

	}

	sort(v.begin(),v.end(),comp);

	

	//初始化 

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

		fa[i]=i;



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

//		printf("(%d,%d) dis=%d\n",v[i].x,v[i].y,v[i].val);

//	}

	//Kruscal

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

		if(find(v[i].x)!=find(v[i].y)){

			merge(v[i].x,v[i].y);

			res+=v[i].val;

		}

	}

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

	return 0;

}


// Faster C++ solution for the same problem (measured speedup: 5.118294597041365x):
#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;

}