// Original C++ solution (slower):
#include <bits/stdc++.h>



using namespace std;

typedef long long ll;

typedef pair<int, ll> P;



struct edge {

  int to; ll cost;

  edge(int t, ll c): to(t), cost(c) {}

};



int n;

vector<edge> G[100001];

ll mincost[100001];

bool used[100001];



ll prim(void) {

  priority_queue<P, vector<P>, greater<P> > que;

  fill(mincost, mincost + n, 1e18);

  mincost[0] = 0;

  que.push(P(0, 0));



  ll res = 0;

  while (!que.empty()) {

    P p = que.top(); que.pop();

    int v = p.second;

    if (used[v] || mincost[v] < p.first) continue;



    used[v] = true;

    res += mincost[v];



    for (int i = 0; i < G[v].size(); i++) {

      edge e = G[v][i];

      if (!used[e.to] && mincost[e.to] > e.cost) {

        mincost[e.to] = e.cost;

        que.push(P(mincost[e.to], e.to));

      }

    }

  }

  return res;

}



int main(void) {

  cin >> n;



  vector<P> x(n), y(n);

  for (int i = 0; i < n; i++) {

    cin >> x[i].first >> y[i].first;

    x[i].second = y[i].second = i;

  }

  sort(x.begin(), x.end());

  sort(y.begin(), y.end());

  

  for (int i = 0; i < n - 1; i++) {

    G[x[i].second].push_back(edge(x[i + 1].second, x[i + 1].first - x[i].first));

    G[x[i + 1].second].push_back(edge(x[i].second, x[i + 1].first - x[i].first));

    G[y[i].second].push_back(edge(y[i + 1].second, y[i + 1].first - y[i].first));

    G[y[i + 1].second].push_back(edge(y[i].second, y[i + 1].first - y[i].first));

  }



  cout << prim() << endl;

  

  return 0;

}

// Optimized solution to the same problem (faster):
#include <bits/stdc++.h>

#define int long long

#define uint unsigned int

#define rep(i, a, b) for (int i = a; i < b; i++)

#define repr(i, a, b) for (int i = a; i >= b; i--)

#define all(a) (a).begin(), (a).end()

#define sz(a) (a).size()

#define pb(a) push_back(a)

#define eb(...) emplace_back(__VA_ARGS__)

#define mp(a, b) make_pair(a, b)

#define mt(...) make_tuple(__VA_ARGS__)

using namespace std;

using pii = pair<int, int>;

constexpr int MOD = 1000000007;

constexpr int INF = 1LL << 30;

constexpr double EPS = 1e-10;



struct edge {

  int f, t, c;

  edge() {}

  edge(int f, int t, int c) : f(f), t(t), c(c) {}

  bool operator < (const edge& e) {

    return c < e.c;

  }

};



int N;

vector<pair<pii, int>> ps;

vector<edge> es;

int par[100010];



int find(int x) {

  return par[x] < 0 ? x : par[x] = find(par[x]);

}



void unite(int x, int y) {

  x = find(x); y = find(y);

  if (x == y) return;

  if (par[x] > par[y]) swap(x, y);

  par[x] += par[y];

  par[y] = x;

}



signed main() {

  cin.tie(0);

  ios_base::sync_with_stdio(false);

  cout << fixed << setprecision(10);

  

  cin >> N;

  rep(i, 0, N) {

    int x, y;

    cin >> x >> y;

    ps.eb(pii(x, y), i);

  }

  sort(all(ps));

  rep(i, 0, N-1) {

    auto p = ps[i];

    auto q = ps[i+1];

    es.eb(p.second, q.second, q.first.first-p.first.first);

  }

  rep(i, 0, N) {

    auto p = ps[i];

    swap(p.first.first, p.first.second);

    ps[i] = p;

  }

  sort(all(ps));

  rep(i, 0, N-1) {

    auto p = ps[i];

    auto q = ps[i+1];

    es.eb(p.second, q.second, q.first.first-p.first.first);

  }



  fill(par, par+N, -1);

  sort(all(es));



  int ans = 0;

  rep(i, 0, sz(es)) {

    int u = find(es[i].f);

    int v = find(es[i].t);

    if (u == v) continue;

    unite(u, v);

    ans += es[i].c;

  }

  cout << ans << endl;



  return 0;

}

// Fastest known solution for this problem: