#pragma GCC optimize ("Ofast")
#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")

#include <bits/stdc++.h>
using namespace std;
using Int = long long;
typedef pair<int,int> P; typedef pair<Int,Int> Pl;
static const int mod = 1e9+7;
#define END {cout<<ans<<'\n'; return 0;}
#define ALL(v) (v).begin(),(v).end()
#define fi first
#define se second
#define Pr(t) priority_queue<t>
#define gPr(t) priority_queue<t,vector<t>,greater<t>>
#define V(t) vector<t>
#define rep(i,n) for(int(i)=0; i<n; i++)
#define rer(i,l,r) for(int i=l; i<=r; i++)
#define gnr(i,l,r) for(int i=r; i>=l; i--)
#define eb emplace_back
#define pri1(a) cout<<(a)<<'\n'
#define pri2(a,n) {rep(pri2i,n-1)cout<<a[pri2i]<<' '; cout<<a[n-1]<<'\n';}
#define prip(p) cout<<p.fi<<' '<<p.se<<'\n'
template<class T> inline bool cmax(T& a, T b) { if (a < b) { a = b; return 1; } return 0; }
template<class T> inline bool cmin(T& a, T b) { if (a > b) { a = b; return 1; } return 0; }

template< typename T >
struct edge {
  int src, to;
  T cost;

  edge(int to, T cost) : src(-1), to(to), cost(cost) {}

  edge(int src, int to, T cost) : src(src), to(to), cost(cost) {}

  edge &operator=(const int &x) {
    to = x;
    return *this;
  }

  operator int() const { return to; }
};

template< typename T >
using Edges = vector< edge< T > >;
template< typename T >
using WeightedGraph = vector< Edges< T > >;
using UnWeightedGraph = vector< vector< int > >;
template< typename T >
using Matrix = vector< vector< T > >;

template< typename T >
T prim(WeightedGraph< T > &g) {
  using Pi = pair< T, int >;
 
  T total = 0;
  vector< bool > used(g.size(), false);
  gPr(Pi)que;
  que.emplace(0, 0);
  while(!que.empty()) {
    Pi p = que.top();
    que.pop();
    if(used[p.se]) continue;
    used[p.se] = true;
    total += p.fi;
    for(auto &e : g[p.se]) {
      que.emplace(e.cost, e.to);
    }
  }
  return total;
}

struct UnionFind {
  vector< int > data;
 
  UnionFind(int sz) {
    data.assign(sz, -1);
  }
 
  bool unite(int x, int y) {
    x = find(x), y = find(y);
    if(x == y) return (false);
    if(data[x] > data[y]) swap(x, y);
    data[x] += data[y];
    data[y] = x;
    return (true);
  }
 
  int find(int k) {
    if(data[k] < 0) return (k);
    return (data[k] = find(data[k]));
  }
 
  int size(int k) {
    return (-data[find(k)]);
  }
};

template< typename T >
T kruskal(Edges< T > &edges, int V) {
  sort(begin(edges), end(edges), [](const edge< T > &a, const edge< T > &b) {
    return (a.cost < b.cost);
  });
  UnionFind tree(V);
  T ret = 0;
  for(auto &e : edges) {
    if(tree.unite(e.src, e.to)) ret += e.cost;
  }
  return (ret);
}

int n,m,_,x,y,q;
string s,sb;
bool ok;
char cf,cb;

signed main(){
  cin.tie(nullptr); ios::sync_with_stdio(false);

  cin>>n; P a[n],b[n],c[n]; Edges<Int>ed;
  rep(i,n){
    cin>>x>>y;
    a[i]=P(x,i);
    b[i]=P(y,i);
    c[i]=P(x,y);
  }
  sort(a,a+n); sort(b,b+n); int fr,to;
  rep(i,n-1){
    fr=a[i].se,to=a[i+1].se;
    ed.eb(fr,to,min(abs(c[fr].fi-c[to].fi),abs(c[fr].se-c[to].se)));
    ed.eb(to,fr,min(abs(c[fr].fi-c[to].fi),abs(c[fr].se-c[to].se)));
    fr=b[i].se,to=b[i+1].se;
    ed.eb(fr,to,min(abs(c[fr].fi-c[to].fi),abs(c[fr].se-c[to].se)));
    ed.eb(fr,to,min(abs(c[fr].fi-c[to].fi),abs(c[fr].se-c[to].se)));
  }
  pri1(kruskal(ed,n));
}

Measured memory_bytes: 12908