← Home
package main

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

type Point struct {
	x int64
	y int64
}

type DSU struct {
	p []int
	r []int
}

func NewDSU(n int) *DSU {
	p := make([]int, n)
	r := make([]int, n)
	for i := 0; i < n; i++ {
		p[i] = i
	}
	return &DSU{p: p, r: r}
}

func (d *DSU) Find(x int) int {
	for d.p[x] != x {
		d.p[x] = d.p[d.p[x]]
		x = d.p[x]
	}
	return x
}

func (d *DSU) Union(a, b int) {
	ra := d.Find(a)
	rb := d.Find(b)
	if ra == rb {
		return
	}
	if d.r[ra] < d.r[rb] {
		ra, rb = rb, ra
	}
	d.p[rb] = ra
	if d.r[ra] == d.r[rb] {
		d.r[ra]++
	}
}

func max64(a, b int64) int64 {
	if a > b {
		return a
	}
	return b
}

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

var (
	n        int
	pts      []Point
	xs       []int64
	ys       []int64
	cols     [][]int
	rows     [][]int
	occupied []bool
	Ux       int
	Uy       int
)

func check(t int64) bool {
	dsu := NewDSU(n)

	for _, list := range cols {
		for i := 1; i < len(list); i++ {
			if pts[list[i]].y-pts[list[i-1]].y <= t {
				dsu.Union(list[i], list[i-1])
			}
		}
	}
	for _, list := range rows {
		for i := 1; i < len(list); i++ {
			if pts[list[i]].x-pts[list[i-1]].x <= t {
				dsu.Union(list[i], list[i-1])
			}
		}
	}

	compOf := make([]int, n)
	compMap := make(map[int]int, n)
	c := 0
	for i := 0; i < n; i++ {
		r := dsu.Find(i)
		id, ok := compMap[r]
		if !ok {
			id = c
			compMap[r] = id
			c++
		}
		compOf[i] = id
	}

	if c == 1 {
		return true
	}
	if c > 4 {
		return false
	}

	allmask := uint8((1 << c) - 1)

	if c == 2 {
		for _, list := range cols {
			for i := 1; i < len(list); i++ {
				a, b := list[i-1], list[i]
				if compOf[a] == compOf[b] {
					continue
				}
				ya, yb := pts[a].y, pts[b].y
				lo := max64(ya+1, yb-t)
				hi := min64(yb-1, ya+t)
				if lo <= hi {
					return true
				}
			}
		}
		for _, list := range rows {
			for i := 1; i < len(list); i++ {
				a, b := list[i-1], list[i]
				if compOf[a] == compOf[b] {
					continue
				}
				xa, xb := pts[a].x, pts[b].x
				lo := max64(xa+1, xb-t)
				hi := min64(xb-1, xa+t)
				if lo <= hi {
					return true
				}
			}
		}
	}

	v := make([]uint8, Ux*Uy)

	for cx, list := range cols {
		pos := 0
		m := len(list)
		base := cx * Uy
		for cy, Y := range ys {
			for pos < m && pts[list[pos]].y < Y {
				pos++
			}
			var mask uint8
			if pos > 0 {
				p := list[pos-1]
				if Y-pts[p].y <= t {
					mask |= uint8(1 << compOf[p])
				}
			}
			a := pos
			if a < m && pts[list[a]].y == Y {
				a++
			}
			if a < m {
				p := list[a]
				if pts[p].y-Y <= t {
					mask |= uint8(1 << compOf[p])
				}
			}
			v[base+cy] = mask
		}
	}

	for cy, list := range rows {
		pos := 0
		m := len(list)
		for cx, X := range xs {
			for pos < m && pts[list[pos]].x < X {
				pos++
			}
			var mask uint8
			if pos > 0 {
				p := list[pos-1]
				if X-pts[p].x <= t {
					mask |= uint8(1 << compOf[p])
				}
			}
			a := pos
			if a < m && pts[list[a]].x == X {
				a++
			}
			if a < m {
				p := list[a]
				if pts[p].x-X <= t {
					mask |= uint8(1 << compOf[p])
				}
			}
			idx := cx*Uy + cy
			if !occupied[idx] && (v[idx]|mask) == allmask {
				return true
			}
		}
	}

	return false
}

func main() {
	in := bufio.NewReaderSize(os.Stdin, 1<<20)
	out := bufio.NewWriterSize(os.Stdout, 1<<20)
	defer out.Flush()

	fmt.Fscan(in, &n)
	pts = make([]Point, n)

	colMap := make(map[int64][]int)
	rowMap := make(map[int64][]int)

	for i := 0; i < n; i++ {
		fmt.Fscan(in, &pts[i].x, &pts[i].y)
		colMap[pts[i].x] = append(colMap[pts[i].x], i)
		rowMap[pts[i].y] = append(rowMap[pts[i].y], i)
	}

	xs = make([]int64, 0, len(colMap))
	for x := range colMap {
		xs = append(xs, x)
	}
	sort.Slice(xs, func(i, j int) bool { return xs[i] < xs[j] })

	ys = make([]int64, 0, len(rowMap))
	for y := range rowMap {
		ys = append(ys, y)
	}
	sort.Slice(ys, func(i, j int) bool { return ys[i] < ys[j] })

	Ux = len(xs)
	Uy = len(ys)

	xid := make(map[int64]int, Ux)
	for i, x := range xs {
		xid[x] = i
	}
	yid := make(map[int64]int, Uy)
	for i, y := range ys {
		yid[y] = i
	}

	cols = make([][]int, Ux)
	for x, list := range colMap {
		sort.Slice(list, func(i, j int) bool {
			return pts[list[i]].y < pts[list[j]].y
		})
		cols[xid[x]] = list
	}

	rows = make([][]int, Uy)
	for y, list := range rowMap {
		sort.Slice(list, func(i, j int) bool {
			return pts[list[i]].x < pts[list[j]].x
		})
		rows[yid[y]] = list
	}

	occupied = make([]bool, Ux*Uy)
	for _, p := range pts {
		occupied[xid[p.x]*Uy+yid[p.y]] = true
	}

	high := int64(2000000000)
	if !check(high) {
		fmt.Fprintln(out, -1)
		return
	}

	low := int64(-1)
	for high-low > 1 {
		mid := (low + high) / 2
		if check(mid) {
			high = mid
		} else {
			low = mid
		}
	}

	fmt.Fprintln(out, high)
}