object Main extends App {
  val sc = new java.util.Scanner(System.in)
  val n = sc.nextInt()
  val xy = List.fill(n)((sc.nextInt(), sc.nextInt())).zipWithIndex
  val e = xy.sortBy(_._1._1).sliding(2).filter{
    case List((p1, _), (p2, _)) => (p1._1 - p2._1).abs <= (p1._2 - p2._2).abs
  }.map{
    case List((p1, idx1), (p2, idx2)) => (idx1, idx2, (p1._1 - p2._1).abs)
  } ++ xy.sortBy(_._1._2).sliding(2).filter{
    case List((p1, _), (p2, _)) => (p1._2 - p2._2).abs <= (p1._1 - p2._1).abs
  }.map{
    case List((p1, idx1), (p2, idx2)) => (idx1, idx2, (p1._2 - p2._2).abs)
  }

  def minimumSpanningTree(n: Int, edges: Seq[(Int, Int, Int)]): Int = {
    class UnionFindTree(n: Int) {
      private val par = Array.tabulate(n)(identity)
      private val rank = Array.fill(n)(1)

      def root(x: Int): Int = {
        var res = x
        var children = List[Int]()
        while (par(res) != res) {
          children ::= res
          res = par(res)
        }

        for (y <- children) {
          par(y) = res
        }
        res
      }

      def unite(x: Int, y: Int): Unit = {
        val xr = root(x)
        val yr = root(y)
        if (xr != yr) {
          if (rank(xr) < rank(yr)) {
            par(xr) = yr
          } else {
            par(yr) = xr
            if (rank(xr) == rank(yr)) {
              rank(xr) += 1
            }
          }
        }
      }
    }

    val uft = new UnionFindTree(n)
    var ans = 0
    for ((x, y, c) <- edges.sortBy(_._3)) {
      if (uft.root(x) != uft.root(y)) {
        uft.unite(x, y)
        ans += c
      }
    }

    ans
  }

  println(minimumSpanningTree(n, e.toList))
}
