package main

import (
	"bufio"
	"fmt"
	"io"
	"os"
	"sort"
	"strconv"
)

var (
	readString func() string
	stdout     *bufio.Writer
)

func init() {
	readString = newReadString(os.Stdin)
	stdout = bufio.NewWriter(os.Stdout)
}

func newReadString(ior io.Reader) func() string {
	r := bufio.NewScanner(ior)
	r.Buffer(make([]byte, 1024), int(1e+11))
	r.Split(bufio.ScanWords)

	return func() string {
		if !r.Scan() {
			panic("Scan failed")
		}
		return r.Text()
	}
}

func readInt() int {
	return int(readInt64())
}

func readInt64() int64 {
	i, err := strconv.ParseInt(readString(), 0, 64)
	if err != nil {
		panic(err.Error())
	}
	return i
}

func readIntSlice(n int) []int {
	b := make([]int, n)
	for i := 0; i < n; i++ {
		b[i] = readInt()
	}
	return b
}

func readLengthAndSlice() []int {
	n := readInt()
	return readIntSlice(n)
}

func printf(f string, args ...interface{}) (int, error) {
	return fmt.Fprintf(stdout, f, args...)
}

func println(args ...interface{}) (int, error) {
	return fmt.Fprintln(stdout, args...)
}

func minInt(a, b int) int {
	if a < b {
		return a
	}
	return b
}

func minUint(a, b uint) uint {
	if a < b {
		return a
	}
	return b
}

func minInt64(a, b int64) int64 {
	if a < b {
		return a
	}
	return b
}

func minUint64(a, b uint64) uint64 {
	if a < b {
		return a
	}
	return b
}

func maxInt(a, b int) int {
	if a < b {
		return b
	}
	return a
}

func maxUint(a, b uint) uint {
	if a < b {
		return b
	}
	return a
}
func maxInt64(a, b int64) int64 {
	if a < b {
		return b
	}
	return a
}

func maxUint64(a, b uint64) uint64 {
	if a < b {
		return b
	}
	return a
}

func absInt(a int) int {
	if a < 0 {
		return -a
	}
	return a
}

func absInt64(a int64) int64 {
	if a < 0 {
		return -a
	}
	return a
}

// readString() string
// readInt() int
// readIntSlice(n int) []int
// readLengthAndSlice() []int
type town struct {
	id   int
	x, y int
}
type townSliceX []town

func (ts townSliceX) Len() int {
	return len(ts)
}
func (ts townSliceX) Less(i, j int) bool {
	return ts[i].x < ts[j].x
}
func (ts townSliceX) Swap(i, j int) {
	ts[i], ts[j] = ts[j], ts[i]
}

type townSliceY []town

func (ts townSliceY) Len() int {
	return len(ts)
}
func (ts townSliceY) Less(i, j int) bool {
	return ts[i].y < ts[j].y
}
func (ts townSliceY) Swap(i, j int) {
	ts[i], ts[j] = ts[j], ts[i]
}

type cost struct {
	val      int
	from, to int
}

func main() {
	defer stdout.Flush()

	n := readInt()
	ts := make([]town, n)
	for i := 0; i < n; i++ {
		ts[i].id = i
		ts[i].x = readInt()
		ts[i].y = readInt()
	}

	E := make([][]cost, n)

	sort.Sort(townSliceX(ts))
	for i := 0; i+1 < n; i++ {
		a := ts[i].id
		b := ts[i+1].id
		c := absInt(ts[i].x - ts[i+1].x)
		E[a] = append(E[a], cost{c, a, b})
		E[b] = append(E[b], cost{c, b, a})
	}

	sort.Sort(townSliceY(ts))
	for i := 0; i+1 < n; i++ {
		a := ts[i].id
		b := ts[i+1].id
		c := absInt(ts[i].y - ts[i+1].y)
		E[a] = append(E[a], cost{c, a, b})
		E[b] = append(E[b], cost{c, b, a})
	}

	v := make(map[int]bool)

	var h []cost
	pq := PriorityQueue(func(i, j int) bool {
		return h[i].val < h[j].val
	})
	pop := func() (cost, bool) {
		if pq.Empty() {
			return cost{}, false
		}
		i := pq.Pop()
		return h[i], true
	}

	push := func(c cost) {
		h = append(h, c)
		pq.Push(len(h) - 1)
	}

	v[0] = true
	for _, c := range E[0] {
		push(c)
	}

	var ans int64
	for len(v) != n {
		e, ok := pop()
		if !ok {
			panic("no edges found")
		}
		if v[e.to] {
			continue
		}
		ans += int64(e.val)
		v[e.to] = true
		for _, c := range E[e.to] {
			push(c)
		}
	}
	println(ans)
}

// PriorityQueue returns a priority queue
func PriorityQueue(prior func(i, j int) bool) *_pq_PQ {
	return &_pq_PQ{
		a:          make([]int, 1, 1024),
		m:          make([]int, 0, 1024),
		prior_func: prior,
	}
}

type _pq_PQ struct {
	a          []int // keeps indexes of the external slice
	m          []int // keeps map to external slice index to a
	prior_func func(i, j int) bool
}

func (pq *_pq_PQ) Empty() bool {
	return len(pq.a) == 1
}

func (pq *_pq_PQ) Pop() int {
	i := 1
	last := len(pq.a) - 1
	ei := pq.a[i]

	pq.a[i] = pq.a[last]
	pq.m[ei] = -1

	pq.a = pq.a[:last]
	pq.shiftdown(i)

	return ei
}

func (pq *_pq_PQ) Push(ei int) {
	pq.a = append(pq.a, ei)
	for len(pq.m) <= ei {
		pq.m = append(pq.m, -1)
	}
	i := len(pq.a) - 1
	pq.m[ei] = i
	pq.shiftup(i)
}

func (pq *_pq_PQ) Fix(ei int) {
	i := pq.m[ei]
	pq.shiftdown(i)
	i = pq.m[ei]
	pq.shiftup(i)
}

func (pq *_pq_PQ) parent(i int) int {
	return i / 2
}

func (pq *_pq_PQ) child(i int) (int, int) {
	l := i * 2
	return l, l + 1
}

func (pq *_pq_PQ) prior(i, j int) bool {
	return pq.prior_func(pq.a[i], pq.a[j])
}

func (pq *_pq_PQ) swap(i, j int) {
	ei := pq.a[i]
	ej := pq.a[j]

	pq.a[i] = ej
	pq.a[j] = ei
	pq.m[ei] = j
	pq.m[ej] = i
}

func (pq *_pq_PQ) shiftdown(i int) {
	n := len(pq.a) - 1
	for {
		if n < i {
			break
		}
		l, r := pq.child(i)
		if n < l {
			break
		}
		if n < r {
			if pq.prior(i, l) {
				break
			}
			pq.swap(l, i)
			i = l
		} else {
			pl := pq.prior(i, l)
			pr := pq.prior(i, r)
			if pl && pr {
				break
			}
			var t int
			if pl && !pr {
				t = r
			} else if !pl && pr {
				t = l
			} else {
				if pq.prior(l, r) {
					t = l
				} else {
					t = r
				}
			}
			pq.swap(t, i)
			i = t
		}
	}
}

func (pq *_pq_PQ) shiftup(i int) {
	for {
		p := pq.parent(i)
		if p == 0 || pq.prior(p, i) {
			break
		}
		pq.swap(p, i)
		i = p
	}
}

func (pq *_pq_PQ) maxDepth(i int) int {
	if len(pq.a) <= i {
		return 0
	}
	l, _ := pq.child(i)
	return 1 + pq.maxDepth(l)
}

func (pq *_pq_PQ) dump(i, h int, acc [][]int) {
	if len(acc) <= h || len(pq.a) <= i {
		return
	}
	acc[h] = append(acc[h], pq.a[i])
	l, r := pq.child(i)
	pq.dump(l, h+1, acc)
	pq.dump(r, h+1, acc)
}

func (pq *_pq_PQ) Dump() [][]int {
	n := pq.maxDepth(1)
	res := make([][]int, n)
	pq.dump(1, 0, res)
	return res
}


Measured memory_bytes: 69888