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 [(i,(i,1)) | i<-[1..n]]
  makepath _ acc [] = acc
  makepath forest acc (((a,b),d):abd)
   | rep1 /= rep2 = makepath _forest (d+acc) abd
   | otherwise = makepath forest acc abd
   where
    (rep1,r1) = untilFix (\(v,_) -> forest!v) (a,0)
    (rep2,r2) = untilFix (\(v,_) -> forest!v) (b,0)
    _forest = if r1>=r2 
               then M.insert b (rep1,r1+1) (M.insert rep2 (rep1,r1+1) forest)
               else M.insert a (rep2,r2+1) (M.insert rep1 (rep2,r2+1) 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 mkedgex xysx (tail xysx)
  edgey = zipWith mkedgey xysy (tail xysy)
  mkedgex ([xi,_],i) ([xj,_],j) = ((min i j, max i j), xj-xi)
  mkedgey ([_,yi],i) ([_,yj],j) = ((min i j, max i j), yj-yi)