fn get_line() -> String {
    let mut s = String::new();
    std::io::stdin().read_line(&mut s).ok();
    s.trim().to_string()
}

fn readln<T>() -> T
    where
        T: std::str::FromStr,
        <T as std::str::FromStr>::Err: std::fmt::Debug {
    get_line().parse().unwrap()
}

fn reads<T>() -> Vec<T>
    where
        T: std::str::FromStr,
        <T as std::str::FromStr>::Err: std::fmt::Debug {
    get_line().split(' ').map(|x| x.parse().unwrap()).collect()
}
struct UFTree {
    roots: Vec<usize>,
    ranks: Vec<usize>,
}

impl UFTree {
    fn new(num: usize) -> UFTree {
        let mut rs = vec![0; num];
        for i in 0..num {
            rs[i] = i;
        }

        UFTree {
            roots: rs,
            ranks: vec![1; num],
        }
    }

    fn find(&mut self, v: usize) -> Option<usize> {
        if self.roots.len() <= v {
            None
        }
        else {
            let vr = self.roots[v];

            if vr == v {
                Some(v)
            }
            else if let Some(r) = self.find(vr) {
                self.roots[v] = r;

                Some(r)
            }
            else {
                None
            }
        }
    }

    fn unite(&mut self, u: usize, v: usize) {
        if let (Some(ur), Some(vr)) = (self.find(u), self.find(v)) {
            if ur == vr {
                return;
            }

            if self.ranks[ur] < self.ranks[vr] {
                self.roots[ur] = vr;
            }
            else {
                self.roots[vr] = ur;

                if self.ranks[ur] == self.ranks[vr] {
                    self.ranks[ur] += 1;
                }
            }
        }
    }

    fn same(&mut self, u: usize, v: usize) -> bool {
        if let (Some(ur), Some(vr)) = (self.find(u), self.find(v)) {
            ur == vr
        }
        else {
            false
        }
    }
}

#[derive(Copy, Clone)]
struct E {
    u: usize,
    v: usize,
    cost: i64,
}

fn main() {
    let n = readln();

    let mut xys = vec![];

    for i in 0..n {
        let x: Vec<usize> = reads();

        xys.push((i, x[0], x[1]));
    }

    let mut vs = xys.clone();

    vs.sort_by(|&lhs, &rhs| {
        lhs.1.cmp(&rhs.1).then(lhs.2.cmp(&rhs.2))
    });

    let mut es = vec![];

    for i in 0..(n - 1) {
        let v1 = vs[i];
        let v2 = vs[i + 1];

        let e = E {u: v1.0, v: v2.0, cost: (v1.1 as i64 - v2.1 as i64).abs()};

        es.push(e);
    }

    vs.sort_by(|&lhs, &rhs| {
        lhs.2.cmp(&rhs.2).then(lhs.1.cmp(&rhs.1))
    });

    for i in 0..(n - 1) {
        let v1 = vs[i];
        let v2 = vs[i + 1];

        let e = E {u: v1.0, v: v2.0, cost: (v1.2 as i64 - v2.2 as i64).abs()};

        es.push(e);
    }

    es.sort_by(|&lhs, &rhs| {
        lhs.cost.cmp(&rhs.cost)
    });

    let mut uf = UFTree::new(n);
    let mut res = 0;

    for e in es {
        if !uf.same(e.u, e.v) {
            uf.unite(e.u, e.v);
            res += e.cost;
        }
    }

    println!("{}", res);
}
