import Data.List
import Data.Maybe
import Data.IntMap.Strict ((!))
import qualified Data.IntMap.Strict as M
import qualified Data.Set as S
import qualified Data.ByteString.Char8 as B
 
_nub = S.toList . S.fromList
readInt = fst . fromJust . B.readInt
untilFix f x = if f x == x then x else untilFix f (f x)

kruskal n edge = makepath uft 0 edge
 where
  uft = M.fromDistinctAscList (zip [1..n] [1..])
  makepath _ acc [] = acc
  makepath forest acc (((a,b),d):abd)
   | rep1 /= rep2 = makepath _forest (d+acc) abd
   | otherwise = makepath forest acc abd
   where
    v1 = min a b
    v2 = max a b
    rep1 = untilFix (forest!) v1
    rep2 = untilFix (forest!) v2
    _forest = M.insert v2 rep1 (M.insert rep2 rep1 forest)
    
main = do
 getLine
 xys <- map (map readInt . B.words) . B.lines <$> B.getContents
 let xyis = zip (_nub xys) [1..]
 let _n = length xyis
 let xysx = sortOn (head.fst) xyis
 let xysy = sortOn (last.fst) xyis
 print (built _n xysx xysy)

built n xysx xysy = kruskal n edge
 where
  edge = sortOn snd (edgex ++ edgey)
  edgex = zipWith mkedge xysx (tail xysx)
  edgey = zipWith mkedge xysy (tail xysy)

mkedge ([xi,yi],i) ([xj,yj],j) = ((i,j), min (abs (xj-xi)) (abs (yj-yi)))