def solve_abc065d():

    from collections import namedtuple

    from heapq import heappush, heappop

    from operator import attrgetter

    from itertools import tee

    import sys



    input = sys.stdin.readline



    City = namedtuple('City', 'x y idx')

    Edge = namedtuple('Edge', 'cost to')

    N = int(eval(input()))



    cities = []

    for city_idx in range(N):

        x, y = list(map(int, input().split()))

        c_ = City(x, y, city_idx)

        cities.append(c_)

    cities_x_asc = sorted(cities, key=attrgetter('x'))

    cities_y_asc = sorted(cities, key=attrgetter('y'))



    graph = tuple(set() for _ in range(N))



    it_x = iter(cities_x_asc)

    gx1, gx2 = tee(it_x, 2)

    next(gx2)

    for c1, c2 in zip(gx1, gx2):

        d_ = c2.x - c1.x

        graph[c1.idx].add(Edge(d_, c2.idx))

        graph[c2.idx].add(Edge(d_, c1.idx))

    # x方向にN-1本の辺を張る



    it_y = iter(cities_y_asc)

    gy1, gy2 = tee(it_y, 2)

    next(gy2)

    for c1, c2 in zip(gy1, gy2):

        d_ = c2.y - c1.y

        graph[c1.idx].add(Edge(d_, c2.idx))

        graph[c2.idx].add(Edge(d_, c1.idx))

    # y方向にN-1本の辺を張る



    # <Prim’s Algorithm>

    # https://tjkendev.github.io/procon-library/python/graph/min_st_prim.html

    # プリム法では、グラフGの1頂点からなる木から始め、

    # 木に含まれる頂点と木に含まれない頂点を繋ぐ辺のうち、

    # 一番コストが小さい辺が繋ぐ(木に含まれない方の)頂点を木に追加する、

    # ことを繰り返すことで最小全域木を求める。

    # G[v] = [w, ...]

    #     グラフG上で頂点vが隣接する辺集合



    start = 0  # 起点とする頂点



    used = [-1] * N

    used[start] = 1



    h = []

    for e_ in graph[start]:

        heappush(h, e_)



    mi = 0

    while h:

        e_ = heappop(h)

        if ~used[e_.to]: continue



        used[e_.to] = 1

        mi += e_.cost



        for ne_ in graph[e_.to]:

            if ~used[ne_.to]: continue

            heappush(h, ne_)



    # miが最小全域木の解



    print(mi)

    return





if __name__ == '__main__':

    solve_abc065d()

class UnionFind:

    def __init__(self, n):

        self.v = [-1] * n



    def find(self, x):

        if self.v[x] < 0:

            return x

        else:

            self.v[x] = self.find(self.v[x])

            return self.v[x]



    def unite(self, x, y):

        x = self.find(x)

        y = self.find(y)



        if x == y:

            return False

        else:

            if self.v[x] > self.v[y]:

                x, y = y, x

            self.v[x] += self.v[y]

            self.v[y] = x

            return True



    def same(self, x, y):

        return self.find(x) == self.find(y)



    def size(self, x):

        return -self.v[self.find(x)]





def main():

    from operator import itemgetter

    import sys

    input = sys.stdin.readline



    N = int(eval(input()))



    ps = []

    xs = set()

    ys = set()

    for i in range(N):

        x, y = list(map(int, input().split()))

        ps.append((x, y))

        xs.add(x)

        ys.add(y)



    xs = tuple(sorted(xs))

    ys = tuple(sorted(ys))



    dx = {e: i for i, e in enumerate(xs)}

    dy = {e: i for i, e in enumerate(ys)}



    uf = UnionFind(N * 2)

    for x, y in ps:

        uf.unite(dx[x], dy[y] + N)



    def make_edges(xs, d, *, add_val=0):

        xes = []

        for x0, x1 in zip(xs, xs[1:]):

            xes.append((abs(x1 - x0), d[x0] + add_val, d[x1] + add_val))

        return xes



    xes = make_edges(xs, dx)

    yes = make_edges(ys, dy, add_val=N)



    # Kruskal

    # 最小コストの辺から順に使用する

    # 同じ連結成分に属していればつながない(閉路を作らない)

    # コスト昇順ソート済みの辺リストを使用する

    ret = 0

    joined = set()

    for cost, a, b in sorted(xes + yes, key=itemgetter(0)):

        if (a in joined) or (b in joined): continue

        if uf.same(a, b): continue

        uf.unite(a, b)

        ret += cost

    print(ret)





if __name__ == '__main__':

    main()

def solve_abc065d():
    from collections import namedtuple
    from heapq import heappush, heappop
    from operator import attrgetter
    from itertools import tee
    import sys

    input = sys.stdin.readline
    City = namedtuple("City", "x y idx")
    Edge = namedtuple("Edge", "cost to")
    N = int(eval(input()))
    cities = []
    for city_idx in range(N):
        x, y = list(map(int, input().split()))
        c_ = City(x, y, city_idx)
        cities.append(c_)
    cities_x_asc = sorted(cities, key=attrgetter("x"))
    cities_y_asc = sorted(cities, key=attrgetter("y"))
    graph = tuple(set() for _ in range(N))
    it_x = iter(cities_x_asc)
    gx1, gx2 = tee(it_x, 2)
    next(gx2)
    for c1, c2 in zip(gx1, gx2):
        d_ = c2.x - c1.x
        graph[c1.idx].add(Edge(d_, c2.idx))
        graph[c2.idx].add(Edge(d_, c1.idx))
    # x方向にN-1本の辺を張る
    it_y = iter(cities_y_asc)
    gy1, gy2 = tee(it_y, 2)
    next(gy2)
    for c1, c2 in zip(gy1, gy2):
        d_ = c2.y - c1.y
        graph[c1.idx].add(Edge(d_, c2.idx))
        graph[c2.idx].add(Edge(d_, c1.idx))
    # y方向にN-1本の辺を張る
    # <Prim’s Algorithm>
    # https://tjkendev.github.io/procon-library/python/graph/min_st_prim.html
    # プリム法では、グラフGの1頂点からなる木から始め、
    # 木に含まれる頂点と木に含まれない頂点を繋ぐ辺のうち、
    # 一番コストが小さい辺が繋ぐ(木に含まれない方の)頂点を木に追加する、
    # ことを繰り返すことで最小全域木を求める。
    # G[v] = [w, ...]
    #     グラフG上で頂点vが隣接する辺集合
    start = 0  # 起点とする頂点
    used = [-1] * N
    used[start] = 1
    h = []
    for e_ in graph[start]:
        heappush(h, e_)
    mi = 0
    while h:
        e_ = heappop(h)
        if ~used[e_.to]:
            continue
        used[e_.to] = 1
        mi += e_.cost
        for ne_ in graph[e_.to]:
            if ~used[ne_.to]:
                continue
            heappush(h, ne_)
    # miが最小全域木の解
    print(mi)
    return


if __name__ == "__main__":
    solve_abc065d()

class UnionFind:
    def __init__(self, n):
        self.v = [-1] * n

    def find(self, x):
        if self.v[x] < 0:
            return x
        else:
            self.v[x] = self.find(self.v[x])
            return self.v[x]

    def unite(self, x, y):
        x = self.find(x)
        y = self.find(y)
        if x == y:
            return False
        else:
            if self.v[x] > self.v[y]:
                x, y = y, x
            self.v[x] += self.v[y]
            self.v[y] = x
            return True

    def same(self, x, y):
        return self.find(x) == self.find(y)

    def size(self, x):
        return -self.v[self.find(x)]


def main():
    from operator import itemgetter
    import sys

    input = sys.stdin.readline
    N = int(eval(input()))
    ps = []
    xs = set()
    ys = set()
    for i in range(N):
        x, y = list(map(int, input().split()))
        ps.append((x, y))
        xs.add(x)
        ys.add(y)
    xs = tuple(sorted(xs))
    ys = tuple(sorted(ys))
    dx = {e: i for i, e in enumerate(xs)}
    dy = {e: i for i, e in enumerate(ys)}
    uf = UnionFind(N * 2)
    for x, y in ps:
        uf.unite(dx[x], dy[y] + N)

    def make_edges(xs, d, *, add_val=0):
        xes = []
        for x0, x1 in zip(xs, xs[1:]):
            xes.append((abs(x1 - x0), d[x0] + add_val, d[x1] + add_val))
        return xes

    xes = make_edges(xs, dx)
    yes = make_edges(ys, dy, add_val=N)
    # Kruskal
    # 最小コストの辺から順に使用する
    # 同じ連結成分に属していればつながない(閉路を作らない)
    # コスト昇順ソート済みの辺リストを使用する
    ret = 0
    joined = set()
    for cost, a, b in sorted(xes + yes, key=itemgetter(0)):
        if (a in joined) or (b in joined):
            continue
        if uf.same(a, b):
            continue
        uf.unite(a, b)
        ret += cost
    print(ret)


if __name__ == "__main__":
    main()

-def solve_abc065d(): -    from collections import namedtuple -    from heapq import heappush, heappop -    from operator import attrgetter -    from itertools import tee +class UnionFind: +    def __init__(self, n): +        self.v = [-1] * n + +    def find(self, x): +        if self.v[x] < 0: +            return x +        else: +            self.v[x] = self.find(self.v[x]) +            return self.v[x] + +    def unite(self, x, y): +        x = self.find(x) +        y = self.find(y) +        if x == y: +            return False +        else: +            if self.v[x] > self.v[y]: +                x, y = y, x +            self.v[x] += self.v[y] +            self.v[y] = x +            return True + +    def same(self, x, y): +        return self.find(x) == self.find(y) + +    def size(self, x): +        return -self.v[self.find(x)] + + +def main(): +    from operator import itemgetter -    City = namedtuple("City", "x y idx") -    Edge = namedtuple("Edge", "cost to") -    cities = [] -    for city_idx in range(N): +    ps = [] +    xs = set() +    ys = set() +    for i in range(N): -        c_ = City(x, y, city_idx) -        cities.append(c_) -    cities_x_asc = sorted(cities, key=attrgetter("x")) -    cities_y_asc = sorted(cities, key=attrgetter("y")) -    graph = tuple(set() for _ in range(N)) -    it_x = iter(cities_x_asc) -    gx1, gx2 = tee(it_x, 2) -    next(gx2) -    for c1, c2 in zip(gx1, gx2): -        d_ = c2.x - c1.x -        graph[c1.idx].add(Edge(d_, c2.idx)) -        graph[c2.idx].add(Edge(d_, c1.idx)) -    # x方向にN-1本の辺を張る -    it_y = iter(cities_y_asc) -    gy1, gy2 = tee(it_y, 2) -    next(gy2) -    for c1, c2 in zip(gy1, gy2): -        d_ = c2.y - c1.y -        graph[c1.idx].add(Edge(d_, c2.idx)) -        graph[c2.idx].add(Edge(d_, c1.idx)) -    # y方向にN-1本の辺を張る -    # <Prim’s Algorithm> -    # https://tjkendev.github.io/procon-library/python/graph/min_st_prim.html -    # プリム法では、グラフGの1頂点からなる木から始め、 -    # 木に含まれる頂点と木に含まれない頂点を繋ぐ辺のうち、 -    # 一番コストが小さい辺が繋ぐ(木に含まれない方の)頂点を木に追加する、 -    # ことを繰り返すことで最小全域木を求める。 -    # G[v] = [w, ...] -    #     グラフG上で頂点vが隣接する辺集合 -    start = 0  # 起点とする頂点 -    used = [-1] * N -    used[start] = 1 -    h = [] -    for e_ in graph[start]: -        heappush(h, e_) -    mi = 0 -    while h: -        e_ = heappop(h) -        if ~used[e_.to]: +        ps.append((x, y)) +        xs.add(x) +        ys.add(y) +    xs = tuple(sorted(xs)) +    ys = tuple(sorted(ys)) +    dx = {e: i for i, e in enumerate(xs)} +    dy = {e: i for i, e in enumerate(ys)} +    uf = UnionFind(N * 2) +    for x, y in ps: +        uf.unite(dx[x], dy[y] + N) + +    def make_edges(xs, d, *, add_val=0): +        xes = [] +        for x0, x1 in zip(xs, xs[1:]): +            xes.append((abs(x1 - x0), d[x0] + add_val, d[x1] + add_val)) +        return xes + +    xes = make_edges(xs, dx) +    yes = make_edges(ys, dy, add_val=N) +    # Kruskal +    # 最小コストの辺から順に使用する +    # 同じ連結成分に属していればつながない(閉路を作らない) +    # コスト昇順ソート済みの辺リストを使用する +    ret = 0 +    joined = set() +    for cost, a, b in sorted(xes + yes, key=itemgetter(0)): +        if (a in joined) or (b in joined): -        used[e_.to] = 1 -        mi += e_.cost -        for ne_ in graph[e_.to]: -            if ~used[ne_.to]: -                continue -            heappush(h, ne_) -    # miが最小全域木の解 -    print(mi) -    return +        if uf.same(a, b): +            continue +        uf.unite(a, b) +        ret += cost +    print(ret) -    solve_abc065d() +    main()