#include <algorithm>
#include <iostream>
#include <utility>
#include <vector>

using namespace std;
using ll = long long;
using Town = pair<ll, ll>;

struct UnionFind {
  vector<ll> par; // par[i]:iの親の番号　(例) par[3] = 2 : 3の親が2

  UnionFind(ll N) : par(N) { //最初は全てが根であるとして初期化
    for(ll i = 0; i < N; i++)
      par[i] = i;
  }

  int root(ll x) { // データxが属する木の根を再帰で得る：root(x) = {xの木の根}
    if(par[x] == x)
      return x;
    return par[x] = root(par[x]); // 根の付替
  }

  void unite(ll x, ll y) { // xとyの木を併合
    if(same(x, y))
      return; // xとyの根が同じ(=同じ木にある)時はそのまま
    par[root(x)] = root(y); // xとyの根が同じでない(=同じ木にない)時：xの根rxをyの根ryにつける
  }

  bool same(ll x, ll y) { // 2つのデータx, yが属する木が同じならtrueを返す
    int rx = root(x);
    int ry = root(y);
    return rx == ry;
  }
};

struct Route {
  ll a;
  ll b;
  ll cost;
};

ll cost(const Town& a, const Town& b) {
  return min(abs(a.first - b.first), abs(a.second - b.second));
}

int main() {
  ll N;
  cin >> N;
  vector<Town> towns(N);
  for(int i = 0; i < N; ++i) {
    cin >> towns[i].first >> towns[i].second;
  }

  vector<Route> routes;

  for(int i = 0; i < N; ++i) {
    for(int j = i + 1; j < N; ++j) {
      routes.push_back({i, j, cost(towns[i], towns[j])});
    }
  }
  sort(routes.begin(), routes.end(), [](const auto& a, const auto& b) { return a.cost < b.cost; });
  /*
  for(auto& r : routes) {
    cout << r.a << " - " << r.b << " : " << r.cost << endl;
  }
  */
  UnionFind uf(N);
  ll totalCost = 0;
  for(auto& r : routes) {
    if(!uf.same(r.a, r.b)) {
      totalCost += r.cost;
      uf.unite(r.a, r.b);
    }
  }
  cout << totalCost << endl;
  return 0;
}