Problem:
Score : 500 points

Problem Statement

There are N points on the 2D plane, i-th of which is located on (x_i, y_i).
There can be multiple points that share the same coordinate.
What is the maximum possible Manhattan distance between two distinct points?

Here, the Manhattan distance between two points (x_i, y_i) and (x_j, y_j) is defined by |x_i-x_j| + |y_i-y_j|.

Constraints

2 \leq N \leq 2 \times 10^5

1 \leq x_i,y_i \leq 10^9

All values in input are integers.

Input

Input is given from Standard Input in the following format:

N
x_1 y_1
x_2 y_2
:
x_N y_N

Output

Print the answer.

Sample Input 1

3
1 1
2 4
3 2

Sample Output 1

4

The Manhattan distance between the first point and the second point is |1-2|+|1-4|=4, which is maximum possible.

Sample Input 2

2
1 1
1 1

Sample Output 2

0

Solution in C# (.NET Core 3.1.201) (judge verdict: Accepted)

using System;
using System.Collections.Generic;
using System.Linq;

namespace ABC178
{
    public class Point : IComparable<Point>
    {
        public int X { get; set; }
        public int Y { get; set; }

        public Point(int x, int y)
        {
            X = x;
            Y = y;
        }

        // Y をマイナスとする
        public int CompareTo(Point other)
        {
            return X + Y - other.X - other.Y;
        }
    }

    public class Point2 : IComparable<Point2>
    {
        public int X { get; set; }
        public int Y { get; set; }

        public Point2(int x, int y)
        {
            X = x;
            Y = y;
        }

        // Y をマイナスとする
        public int CompareTo(Point2 other)
        {
            return X - Y - other.X + other.Y;
        }
    }
    class Program3
    {
        static void Main()
        {
            // 右上、右下
            var n = int.Parse(Console.ReadLine());
            var points = new Point[n];
            var points2 = new Point2[n];
            for (var i = 0; i < n; i++)
            {
                var tmp = Console.ReadLine().Split(' ').Select(int.Parse);
                points[i] = new Point(tmp.First(), tmp.Last());
                points2[i] = new Point2(tmp.First(), tmp.Last());
            }

            Sort.MergeSort(points);
            Sort.MergeSort(points2);

            var max1 = Math.Abs(points.Last().X - points.First().X) + Math.Abs(points.Last().Y - points.First().Y);
            var max2 = Math.Abs(points2.Last().X - points2.First().X) + Math.Abs(points2.Last().Y - points2.First().Y);
            Console.WriteLine(Math.Max(max1, max2));
        }
    }

    static class Sort
    {
        /// <summary>
        /// a と b の中身を入れ替える。
        /// </summary>
        /// <param name="a">オペランドa</param>
        /// <param name="b">オペランドb</param>
        public static void Swap<T>(ref T a, ref T b)
        {
            T c = a; a = b; b = c;
        }

        /// <summary>
        /// クイックソートやマージソート → 挿入ソートに切り替える配列長の閾値。
        /// </summary>
        const int THREASHOLD = 64;

        /// <summary>
        /// 挿入ソート。
        /// 配列のどこからどこまでをソートするかを指定するバージョン。
        /// </summary>
        /// <param name="a">対象の配列</param>
        /// <param name="first">ソート対象の先頭インデックス</param>
        /// <param name="last">ソート対象の末尾インデックス</param>
        static void InsertSort<T>(T[] a, int first, int last)
          where T : IComparable<T>
        {
            for (int i = first + 1; i <= last; i++)
                for (int j = i; j > first && a[j - 1].CompareTo(a[j]) > 0; --j)
                    Swap(ref a[j], ref a[j - 1]);
        }

        /// <summary>
        /// マージソート。
        /// </summary>
        /// <param name="a">対象の配列</param>
        public static void MergeSort<T>(T[] a)
          where T : IComparable<T>
        {
            T[] work = new T[a.Length / 2];
            MergeSort(a, 0, a.Length, work);
        }

        /// <summary>
        /// マージソート。
        /// 配列のどこからどこまでをソートするかを指定するバージョン。
        /// </summary>
        /// <param name="a">対象の配列</param>
        /// <param name="begin">ソート対象部分の先頭</param>
        /// <param name="end">ソート対象部分の末尾＋1</param>
        /// <param name="work">作業領域。a の 1/2 のサイズが必要。</param>
        static void MergeSort<T>(T[] a, int begin, int end, T[] work)
          where T : IComparable<T>
        {
            if (end - begin < THREASHOLD)
            {
                InsertSort(a, begin, end - 1);
                return;
            }

            int mid = (begin + end) / 2;
            MergeSort(a, begin, mid, work);
            MergeSort(a, mid, end, work);
            Merge(a, begin, mid, end, work);
        }

        /// <summary>
        /// 配列 a の、[begin, mid) の部分と [mid, end) の部分をマージ。
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="a">マージ対象の配列</param>
        /// <param name="begin1">aの先頭</param>
        /// <param name="mid">aの分割点</param>
        /// <param name="end">aの末尾＋1</param>
        /// <param name="work">作業領域</param>
        static void Merge<T>(T[] a, int begin, int mid, int end, T[] work)
          where T : IComparable<T>
        {
            int i, j, k;

            for (i = begin, j = 0; i != mid; ++i, ++j) work[j] = a[i];

            mid -= begin;
            for (j = 0, k = begin; i != end && j != mid; ++k)
            {
                if (a[i].CompareTo(work[j]) < 0)
                {
                    a[k] = a[i];
                    ++i;
                }
                else
                {
                    a[k] = work[j];
                    ++j;
                }
            }

            for (; i < end; ++i, ++k) a[k] = a[i];
            for (; j < mid; ++j, ++k) a[k] = work[j];
        }
    }
}