use ordered_float::OrderedFloat;
use proconio::input;
#[allow(unused_imports)]
use proconio::marker::*;
#[allow(unused_imports)]
use std::cmp::*;
#[allow(unused_imports)]
use std::collections::*;
#[allow(unused_imports)]
use std::f64::consts::*;

#[allow(unused)]
const INF: usize = std::usize::MAX / 4;
#[allow(unused)]
const M: usize = 1000000007;

#[allow(unused_macros)]
macro_rules! debug {
    ($($a:expr),* $(,)*) => {
        #[cfg(debug_assertions)]
        eprintln!(concat!($("| ", stringify!($a), "={:?} "),*, "|"), $(&$a),*);
    };
}

#[derive(Clone, Copy)]
pub struct Point {
    pub x: isize,
    pub y: isize,
}

fn anticlockwise(p0: Point, p1: Point, p2: Point) -> bool {
    let c = (p2.x - p0.x) * (p1.y - p0.y) - (p1.x - p0.x) * (p2.y - p0.y);
    c < 0
}

fn graham_scan(points: &[Point]) -> Result<Vec<(Point, usize)>, String> {
    let n = points.len();
    if n < 3 {
        return Ok(vec![]);
    }
    let p0 = *points.iter().min_by_key(|&p| (p.y, p.x)).unwrap();
    let mut indices = (0..n).collect::<Vec<_>>();
    indices.sort_by_key(|&i| {
        (
            OrderedFloat::from(((points[i].y - p0.y) as f64).atan2((points[i].x - p0.x) as f64)),
            Reverse(OrderedFloat((points[i].x - p0.x) as f64)),
        )
    });
    let mut stack = vec![];
    for &i in &indices[0..3] {
        stack.push((points[i], i));
    }
    for &i in &indices[3..n] {
        loop {
            let m = stack.len();
            if m < 2 || anticlockwise(stack[m - 2].0, stack[m - 1].0, points[i]) {
                break;
            }
            stack.pop();
        }
        stack.push((points[i], i));
    }
    Ok(stack)
}

fn dist(i: usize, j: usize, xy: &Vec<(isize, isize)>) -> isize {
    let (x1, y1) = xy[i];
    let (x2, y2) = xy[j];
    (x1 - x2).abs() + (y1 - y2).abs()
}

fn main() {
    input! {
        n: usize,
        xy: [(isize, isize); n],
    }
    // let mut d = 0;
    // for i in 0..n {
    //     for j in 0..i {
    //         if dist(i, j, &xy) >= d {
    //             debug!(i, j);
    //         }
    //         d = max(d, dist(i, j, &xy));
    //     }
    // }
    // println!("{}", d);

    let points = xy
        .iter()
        .map(|&(x, y)| Point { x, y })
        .collect::<Vec<Point>>();
    let ch = graham_scan(&points).unwrap();

    if ch.len() == 0 {
        let mut d = 0;
        for i in 0..n {
            for j in 0..i {
                d = max(d, dist(i, j, &xy));
            }
        }
        println!("{}", d);
        return;
    }

    if ch.len() < 10000 {
        let mut d = 0;
        for i in 0..ch.len() {
            for j in 0..i {
                d = max(d, dist(ch[i].1, ch[j].1, &xy));
            }
        }
        println!("{}", d);
        return;
    }

    let mut p = vec![];
    for &(_, i) in &ch {
        debug!(xy[i]);
        p.push(i);
    }
    for &(_, i) in &ch {
        p.push(i);
    }
    debug!(p);

    let mut result = 0;
    let mut l = 0;
    for k in 0..ch.len() {
        if l < k {
            l = k;
        }
        let mut d0 = dist(p[k], p[l], &xy);
        let d = loop {
            if l + 1 >= p.len() {
                break d0;
            }
            let d = dist(p[k], p[l + 1], &xy);
            debug!(k, l + 1);
            debug!(xy[p[k]], xy[p[l + 1]]);
            debug!(p[k], p[l + 1], d, d0);
            if d <= d0 {
                if l > k {
                    l -= 1;
                }
                break d0;
            }
            l += 1;
            d0 = d;
        };
        debug!(d);
        result = max(result, d);
    }
    println!("{}", result);
}


Measured memory_bytes: 15328