#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:
  int vn;
  int sumcost = 0;
  vector<vector<pair<int, int>>> g;
  Graph(int n) {
    vn = n;
    g.resize(n);
  }
  virtual void con(int a, int b, int w) = 0;
  int getWeight(int f, int t) {
    auto itr = lower_bound((g[f]).begin(), (g[f]).end(), make_pair(t, INT_MIN));
    if (itr != g[f].end()) return itr->second;
    return INT_MIN;
  }
  int Costsum() { return sumcost; }
  void scan(int edcount, bool oindexed, bool w) {
    for (int i = (0); (edcount) > i; i++) {
      int a, b, c = 1;
      scanf("%d %d", &a, &b);
      if (w) scanf("%d", &c);
      con(a - oindexed, b - oindexed, c);
    }
  }
};
class BiDGraph : public Graph {
 public:
  BiDGraph(int n) : Graph(n) {}
  void con(int a, int b, int w = 1) {
    g[a].push_back({b, w});
    g[b].push_back({a, w});
    sumcost++;
  }
};
int TDiam(BiDGraph& graph) {
  function<pair<int, int>(int, int, int)> dfs = [&](int cur, int dis,
                                                    int from) {
    pair<int, int> Max = {dis, cur};
    for (int i = (0); ((int)graph.g[cur].size()) > i; i++) {
      if (graph.g[cur][i].first != from) {
        Max = max(
            Max, dfs(graph.g[cur][i].first, dis + graph.g[cur][i].second, cur));
      }
    }
    return Max;
  };
  pair<int, int> S = dfs(0, 0, -1);
  pair<int, int> G = dfs(S.second, 0, -1);
  return G.first;
}
template <typename T>
class Lazy_Segment_Tree {
 public:
  vector<T> data, lazy;
  int n;
  Lazy_Segment_Tree(int a) : n(1) {
    while (n < a) n *= 2;
    data.resize(n * 2 - 1);
    lazy.resize(n * 2 - 1);
  }
  void add(int a, int b, T ad, int num = 0, int base = 1) {
    int l = (num + 1 - base) * (n / base), r = l + n / base;
    if (a == l && b == r)
      lazy[num] += ad;
    else {
      data[num] += ad * (b - a);
      int nr = (l + r) / 2;
      if (nr > a) add(a, min(b, nr), ad, num * 2 + 1, base * 2);
      if (nr < b) add(max(a, nr), b, ad, num * 2 + 2, base * 2);
    }
  }
  T sum(int a, int b, int num = 0, int base = 1) {
    int l = (num + 1 - base) * (n / base), r = l + n / base;
    data[num] += lazy[num] * (r - l);
    if (num < n - 1)
      lazy[num * 2 + 1] += lazy[num], lazy[num * 2 + 2] += lazy[num];
    lazy[num] = T();
    if (a == l && b == r)
      return data[num];
    else {
      int nr = (l + r) / 2;
      T ret = T();
      if (nr > a) ret += sum(a, min(b, nr), num * 2 + 1, base * 2);
      if (nr < b) ret += sum(max(a, nr), b, num * 2 + 2, base * 2);
      return ret;
    }
  }
};
class Heavy_Light_Decomposition {
 public:
  BiDGraph g, compg;
  vector<int> sz, depth, chain, par;
  int bn = 0;
  vector<int> bvn, inbn;
  vector<vector<int>> bv;
  Heavy_Light_Decomposition(BiDGraph graph, int root)
      : g(graph),
        compg(graph.vn),
        sz(graph.vn, 1),
        depth(graph.vn),
        chain(graph.vn),
        par(graph.vn),
        bvn(graph.vn),
        inbn(graph.vn) {
    getsz(root, root);
    bv.push_back(vector<int>());
    HLD(root, -1, root, 0);
  }
  int getsz(int cur, int p) {
    par[cur] = p;
    for (auto itr : g.g[cur])
      if (p != itr.first)
        depth[itr.first] = depth[cur] + 1, sz[cur] += getsz(itr.first, cur);
    return sz[cur];
  }
  void HLD(int cur, int p, int head, int num) {
    chain[cur] = head, bvn[cur] = num;
    inbn[cur] = bv[num].size(), bv[num].push_back(cur);
    pair<int, int> Maxc = {-1, -1};
    for (auto itr : g.g[cur])
      if (itr.first != p) Maxc = max(Maxc, {sz[itr.first], itr.first});
    for (auto itr : g.g[cur])
      if (itr.first != p) {
        int nb = num;
        if (itr.first != Maxc.second) {
          bv.push_back(vector<int>());
          nb = ++bn;
        }
        HLD(itr.first, cur, itr.first == Maxc.second ? head : itr.first, nb);
      }
  }
  int lca(int a, int b) {
    if (chain[a] == chain[b]) return depth[a] < depth[b] ? a : b;
    if (depth[chain[a]] > depth[chain[b]]) return lca(par[chain[a]], b);
    return lca(a, par[chain[b]]);
  }
  void for_each_edge(int a, int b, function<void(int, int)> func) {
    if (chain[a] == chain[b])
      return func(inbn[a] < inbn[b] ? a : b, inbn[a] < inbn[b] ? b : a);
    if (depth[chain[a]] < depth[chain[b]]) swap(a, b);
    for_each_edge(a, chain[a], func), for_each_edge(par[chain[a]], b, func);
  }
};
struct UnionFind {
  vector<int> data;
  UnionFind(int size) : data(size, -1) {}
  bool unionSet(int x, int 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(int x, int y) { return root(x) == root(y); }
  int root(int x) { return data[x] < 0 ? x : data[x] = root(data[x]); }
  bool isroot(int x) { return data[x] < 0; }
  int size(int x) { return -data[root(x)]; }
};
BiDGraph Kruskal(BiDGraph g) {
  UnionFind uf(g.vn);
  priority_queue<pair<int, pair<int, int>>, vector<pair<int, pair<int, int>>>,
                 greater<pair<int, pair<int, int>>>>
      que;
  for (int i = (0); (g.g.size()) > i; i++) {
    for (auto itr : g.g[i]) {
      int f = i, t = itr.first;
      if (f < t) swap(f, t);
      que.push({itr.second, {f, t}});
    }
  }
  BiDGraph MST(g.vn);
  int alcou = 0;
  while (alcou < g.vn) {
    pair<int, pair<int, int>> 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() {
  int n;
  scanf("%d", &n);
  vector<pair<int, int>> pos(n);
  vector<pair<int, int>> x(n), y(n);
  for (int i = (0); (n) > i; i++) {
    scanf("%d %d", &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 (int 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 (int 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;
}
