#include <bits/stdc++.h>
using namespace std;
long long gcd(long long a, long long b) {
  if (b == 0) return a;
  return gcd(b, a % b);
}
template <typename A, size_t N, typename T>
void Fill(A (&array)[N], const T &val) {
  std::fill((T *)array, (T *)(array + N), val);
}
class Graph {
 public:
  long long vn;
  long long sumcost = 0;
  vector<vector<pair<long long, long long>>> g;
  Graph(long long n) {
    vn = n;
    g.resize(n);
  }
  virtual void con(long long a, long long b, long long w) = 0;
  long long Costsum() { return sumcost; }
  void scan(long long edcount, bool oindexed, bool w) {
    for (long long i = (0); (edcount) > i; i++) {
      long long a, b, c = 1;
      scanf("%d %d", &a, &b);
      if (w) scanf("%d", &c);
      con(a - (long long)oindexed, b - (long long)oindexed, c);
    }
  }
};
class BiDGraph : public Graph {
 public:
  BiDGraph(long long n) : Graph(n) {}
  void con(long long a, long long b, long long w = 1) {
    g[a].push_back({b, w});
    g[b].push_back({a, w});
    sumcost++;
  }
};
struct UnionFind {
  vector<long long> data;
  UnionFind(long long size) : data(size, -1) {}
  bool unionSet(long long x, long long y) {
    x = root(x);
    y = root(y);
    if (x != y) {
      if (data[y] < data[x]) swap(x, y);
      data[x] += data[y];
      data[y] = x;
    }
    return x != y;
  }
  bool findSet(long long x, long long y) { return root(x) == root(y); }
  long long root(long long x) {
    return data[x] < 0 ? x : data[x] = root(data[x]);
  }
  bool isroot(long long x) { return data[x] < 0; }
  long long size(long long x) { return -data[root(x)]; }
};
BiDGraph Kruskal(BiDGraph g) {
  UnionFind uf(g.vn);
  priority_queue<pair<long long, pair<long long, long long>>,
                 vector<pair<long long, pair<long long, long long>>>,
                 greater<pair<long long, pair<long long, long long>>>>
      que;
  for (long long i = (0); (g.g.size()) > i; i++) {
    for (auto itr : g.g[i]) {
      long long f = i, t = itr.first;
      if (f < t) swap(f, t);
      que.push({itr.second, {f, t}});
    }
  }
  BiDGraph MST(g.vn);
  long long alcou = 0;
  while (alcou < g.vn) {
    pair<long long, pair<long long, long long>> cur = que.top();
    que.pop();
    if (uf.findSet(cur.second.first, cur.second.second)) continue;
    if (uf.data[cur.second.first] == -1) alcou++;
    if (uf.data[cur.second.second] == -1) alcou++;
    uf.unionSet(cur.second.first, cur.second.second);
    MST.con(cur.second.first, cur.second.second);
  }
  return MST;
}
signed main() {
  long long n;
  scanf("%lld", &n);
  vector<pair<long long, long long>> pos(n);
  vector<pair<long long, long long>> x(n), y(n);
  for (long long i = (0); (n) > i; i++) {
    scanf("%lld %lld", &pos[i].first, &pos[i].second);
    x[i] = {pos[i].first, i};
    y[i] = {pos[i].second, i};
  }
  sort((x).begin(), (x).end());
  sort((y).begin(), (y).end());
  BiDGraph g(n);
  for (long long i = (1); (n) > i; i++) {
    g.con(x[i - 1].second, x[i].second, abs(x[i].first - x[i - 1].first));
    g.con(y[i - 1].second, y[i].second, abs(y[i].first - y[i - 1].first));
  }
  BiDGraph mst(Kruskal(g));
  long long ans = 0;
  for (long long i = (0); (n) > i; i++) {
    for (auto itr : mst.g[i])
      ans += min(abs(pos[i].first - pos[itr.first].first),
                 abs(pos[i].second - pos[itr.first].second));
  }
  printf("%lld\n", ans / 2);
  return 0;
}
