#include<bits/stdc++.h>

#define MOD_1_000_000_007 (1000000007LL)
#define LINF (1LL<<60)
#define rep(i, n)   for (long long i = 0; i <  (long long)(n); i++)
#define rep1(i, n)  for (long long i = 1; i <  (long long)(n); i++)
#define rep2(i, n)  for (long long i = 2; i <  (long long)(n); i++)
#define rep0c(i, n) for (long long i = 0; i <= (long long)(n); i++)
#define rep1c(i, n) for (long long i = 1; i <= (long long)(n); i++)
#define rep2c(i, n) for (long long i = 2; i <= (long long)(n); i++)
#define repc0(n, i) for (long long i = (long long)(n); i >= 0; i--)
#define repc1(n, i) for (long long i = (long long)(n); i >= 1; i--)
#define repc2(n, i) for (long long i = (long long)(n); i >= 2; i--)
#define REP(i, n, m) for (long long i = (long long)(n); i < (long long)(m); i++)

namespace graph {
  static const long long V_MAX = 100010;
  static const long long INF = (1LL<<60);
  struct edge {
    long long from, to, dist;
  };

  long long V_SIZE = 0;
  std::vector<edge> G[V_MAX];

  std::vector<edge> kruskal() {
    struct DisjointSet {
      std::map<int, int> parent, rank, num;

      void makeSet(int x) {
        parent[x] = x;
        rank[x] = 0;
        num[x] = 1;
      }

      bool same(int x, int y) {
        return findSet(x) == findSet(y);
      }

      void unite(int x, int y) {
        link(findSet(x), findSet(y));
      }

      void link(int x, int y) {
        if(rank[x] < rank[y]) {
          parent[x] = y;
          num[y] += num[x];
        } else {
          parent[y] = x;
          num[x] += num[y];
          if(rank[x] == rank[y]) rank[x]++;
        }
      }

      int numberOf(int x) {
        return num[findSet(x)];
      }

      int findSet(int x) {
        if(x == parent[x]) return x;
        else return parent[x] = findSet(parent[x]);
      }
    };
    struct EdgeComparator {
      bool operator()(const edge& lhs, const edge& rhs) {
        return lhs.dist > rhs.dist;
      }
    };
    DisjointSet ds;
    std::priority_queue<edge, std::vector<edge>, EdgeComparator> que;
    for(long long i = 0; i < V_SIZE; i++) {
      ds.makeSet(i);
      for(const edge& e : G[i]) {
        que.push(e);
      }
    }
    std::vector<edge> mst;
    while(!que.empty()) {
      edge e = que.top(); que.pop();
      if(!ds.same(e.from, e.to)) {
        ds.unite(e.from, e.to);
        mst.push_back(e);
      }
    }
    return mst;
  }
}

namespace solver {
  using namespace std;
  typedef long long ll;
  typedef tuple<ll, ll, ll> P;

  static const ll MAX = 100010LL;
  ll N;
  vector<P> E;

  void init() {
    scanf("%lld", &N);
    ll x, y;
    rep(i, N) {
      scanf("%lld %lld", &x, &y);
      x--;
      y--;
      E.push_back(make_tuple(x, y, i));
    }
  }

  void solve() {
    using namespace graph;
    sort(E.begin(), E.end(), [](const auto& lhs, const auto& rhs) { return get<0>(lhs) < get<0>(rhs); });
    rep(i, N-1) {
      auto s = E[i];
      auto t = E[i+1];
      G[i].push_back({get<2>(s), get<2>(t), abs(get<0>(s)-get<0>(t))});
    }
    sort(E.begin(), E.end(), [](const auto& lhs, const auto& rhs) { return get<1>(lhs) < get<1>(rhs); });
    rep(i, N-1) {
      auto s = E[i];
      auto t = E[i+1];
      G[i].push_back({get<2>(s), get<2>(t), abs(get<1>(s)-get<1>(t))});
    }
    V_SIZE = N;
    auto mst = kruskal();
    ll ans = 0;
    for(const auto& e : mst) ans += e.dist;
    cout << ans << endl;
  }
}

int main() {
  solver::init();
  solver::solve();
  return 0;
}

Measured memory_bytes: 37612