use std::vec::Vec;
use std::cmp::*;

fn read<T: std::str::FromStr>() -> T {
    let mut s = String::new();
    std::io::stdin().read_line(&mut s).ok();
    s.trim().parse().ok().unwrap()
}

fn read_vec<T: std::str::FromStr>() -> Vec<T> {
    read::<String>().split_whitespace().map(|e| e.parse().ok().unwrap()).collect()
}

fn main() {
    let n: usize = read();
    let mut position = Vec::new();
    let mut edges = Vec::new();
    for i in 0..n {
        let v: Vec<i64> = read_vec();
        position.push((v[0], v[1], i));
    }

    position.sort_by(|a, b| a.0.cmp(&b.0));
    for i in 0..n-1 {
        let (a, b, v1) = position[i];
        let (c, d, v2) = position[i+1];
        let cost = min((a - c).abs(), (b - d).abs());
        edges.push((v1, v2, cost));
    }


    position.sort_by(|a, b| a.1.cmp(&b.1));
    for i in 0..n-1 {
        let (a, b, v1) = position[i];
        let (c, d, v2) = position[i+1];
        let cost = min((a - c).abs(), (b - d).abs());
        edges.push((v1, v2, cost));
    }

    let ans = kruskal(&mut edges, n);
    println!("{}", ans);
}


use std::cmp::*;

// 最小全域木の重みの総和を計算する
// edgesは辺の集合 (source, target, cost), n: 頂点数
// グラフは無向グラフ
fn kruskal(edges: &mut Vec<(usize, usize, i64)>, n: usize) -> i64 {
    let mut res = 0;
    let mut uf = UnionFind::new(n);

    edges.sort_by(|a, b| a.2.cmp(&b.2));

    for &mut (source, target, cost) in edges {
        if !uf.connected(source as i64, target as i64) {
            uf.connect(source as i64, target as i64);
            res += cost;
        }
    }
    
    res
}


pub struct UnionFind {
  // 親のノードの番号を書くのする。親だった場合は-(その集合のサイズ)
  pub parent: Vec<i64>,
}


impl UnionFind {
  // コンストラクター
  pub fn new(n: usize) -> UnionFind {
    return UnionFind {parent: vec![-1; n]};
  }

  // aがどのグループに属しているか調べる
  // 属している木の根を返す
  // 帰り際に要素を直接、根に接続
  pub fn root(&mut self, a: i64) -> i64 {

    if self.parent[a as usize] < 0 {
      return a;
    }
    // aに属してる集合の根にaを直接つなぐ
    let tmp = self.parent[a as usize];
    self.parent[a as usize] = self.root(tmp);

    return self.parent[a as usize];
  }

  // 自分のいるグループの頂点数を調べる
  pub fn size(&mut self, a: i64) -> i64 {
    let tmp = self.root(a) as usize;
    return -self.parent[tmp];
  }

  // aにbをくっつける
  // 接続できたらtrue,　すでに接続済ならfalse 
  pub fn connect(&mut self, a: i64, b: i64) -> bool {
    let mut at = self.root(a);
    let mut bt = self.root(b);

    if at == bt {
      // すでにくっついてるからくっつけない
      return false;
    }

    // 大きい方aに小さい方bをくっつける
    // 大小が逆だったらひっくり返す
    if self.size(at) < self.size(bt) {
      let temp = at;
      at = bt;
      bt = temp;
    }

    // aのサイズを更新する
    self.parent[at as usize] += self.parent[bt as usize];
    // bの親をaに更新する
    self.parent[bt as usize] = at;
    return true
  }

  // UnionFind同士が等しいかどうか判定する
  pub fn equal(&self, that: UnionFind) -> bool {
    let l: usize = that.parent.len();

    if self.parent.len() != l {
      return false;
    }

    for i in 0..l {
      if self.parent[i] != that.parent[i] {
        return false;
      }
    }
    return true;
  }
  // aとbが接続しているかどうかを判定する
  pub fn connected(&mut self, a: i64, b: i64 ) -> bool {
    self.root(a) == self.root(b)
  }
}



Measured memory_bytes: 18416