import Data.Array.IO
import Data.List
import Data.Ord
import Control.Monad

type UnionFindIO = IOArray Int (Int,Int)

newUFIO :: Int -> IO UnionFindIO
newUFIO n = newListArray (1,n) (zip [1..n] (repeat 1))

findUFIO :: Int -> UnionFindIO -> IO Int
findUFIO x uf = do
  (parent,size) <- readArray uf x
  if parent == x then
    return x
    else do
    next <- findUFIO parent uf
    writeArray uf x (next,size)
    return next

sameUFIO :: Int -> Int -> UnionFindIO -> IO Bool
sameUFIO x y uf = do
  xx <- findUFIO x uf
  yy <- findUFIO y uf
  return $ xx == yy

uniteUFIO :: Int -> Int -> UnionFindIO -> IO ()
uniteUFIO x y uf = do
  xx <- findUFIO x uf
  yy <- findUFIO y uf
  (_,xs) <- readArray uf xx
  (_,ys) <- readArray uf yy

  if xx == yy then
    return ()
    else if xs < ys then do
    writeArray uf xx (yy,0)
    else if xs > ys then do
    writeArray uf yy (xx,0)
    else do
    writeArray uf yy (xx,0)
    writeArray uf xx (xx,xs+1)


type City = (Int,(Int,Int))

kruskal :: [City] -> [(City,City)] -> IO Int
kruskal nodes edges = do
  let sorted = sortBy comp (map (\((i,ci),(j,cj)) -> (i,j,dist ci cj)) edges)

  uf <- newUFIO (length nodes)

  let
    kruskal' e@(i,j,c) = do
      same <- sameUFIO i j uf
      if same then
        return 0
        else do
        uniteUFIO i j uf
        return c
        
  mapM kruskal' sorted >>= return . sum
  where
    comp (_,_,c1) (_,_,c2) = compare c1 c2
    dist (x1,y1) (x2,y2) = min (abs $ x1-x2) (abs $ y1-y2)

listToTuple2 (a:b:_) = (a,b)

main = do
  n <- readLn :: IO Int
  nodes <- getContents >>= return . zip [1..] . map (listToTuple2 . map read . words) . lines :: IO [(Int,(Int,Int))]
  let roads = f (sortBy (comparing (fst . snd)) nodes) ++
              f (sortBy (comparing (snd . snd)) nodes)

  print =<< kruskal nodes roads

  where
    f (_:[]) = []
    f (x:y:xs) = (x,y) : f (y:xs)