Problem:
博覧会

問題

JOI 市では,とある大規模な博覧会を開催することになった.

今回の博覧会には 2 つのテーマがあり,JOI 市にある N 個の展示施設でそれぞれ,
2 つのテーマのうちどちらか一方に沿った展示を行う予定である.

施設の位置は平面座標 (x, y) で表される.位置 (x, y) にある施設から (x′ , y′) にある施設まで移動するためには, |x − x′| + |y − y′| だけの時間がかかる (整数 a に対して,
|a| で a の絶対値を表す).同一テーマ内での統一感を出すため,および一方のテーマのみに関心を持つ人に不便を感じさせないために,同一のテーマで展示を行っている 2 つの施設の間の移動時間がなるべく短くなるようにテーマを割りふりたい.すべての展示施設に同じテーマを割りふらない限り, どのようにテーマを割りふってもよい.

同一のテーマで展示を行っている 2 つの施設の間の移動時間の最大値を M とする. N 個の展示施設の位置が与えられたとき, M の最小値を求めるプログラムを作成せよ.

入力

入力の 1 行目には, 施設の個数 N(3 ≤ N ≤ 100000 = 105 ) が書かれている.入力のi + 1 行目 (1 ≤ i ≤ N) には,各施設の座標を表す 2 つの整数 xi, yi (|xi| ≤ 100000 = 105, |yi| ≤ 100000 = 105 ) が空白区切りで書かれている.これは,i 個目の施設の座標が(xi , yi) であることを表す. 同一の座標に 2 つ以上の施設が存在することはない.

採点用データのうち,配点の 40% 分については, N ≤ 2000 である.

出力

出力は 1 行のみからなる.同一のテーマで展示を行っている 2 つの施設間の移動時間の最大値 M の最小値を出力せよ.

入出力例

入力例 1

5
0 0
1 0
-1 -2
0 1
-1 1

出力例 1

3

この場合,たとえば座標 (0, 0), (1, 0), (0, 1) にある施設に一方のテーマを,(−1, −2),
(−1, 1) にある施設にもう一方のテーマを割りふると,同一のテーマで展示を行う 2
つの施設間の移動時間はすべて 3 以下になる.移動時間をすべて 2 以下にすることはできないので,3 を出力する.

上記問題文と自動審判に使われるデータは、情報オリンピック日本委員会が作成し公開している問題文と採点用テストデータです。

Solution in C (judge verdict: Accepted)

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>

typedef struct {
    int x, y;
} POINT;

POINT add[100000], minus[100000];
char group[2][100000];
int n;

int comp(const void *a, const void *b)
{
    POINT p, q;
    
    p = *(POINT *)a;
    q = *(POINT *)b;
    
    return (p.x - q.x);
}

int canDivide(int piv)
{
    int i;
    int a, b;
    
    for (i = 0; i < n; i++){
        group[0][i] = group[1][i] = 2;
    }
    group[0][add[0].y] = 0;
    //suppose distance will be given by |c[0][i] - c[0][j]|
    
    for (i = 0; i < n; i++){
        if (abs(add[i].x - add[0].x) > piv && abs(add[i].x - add[n - 1].x) > piv){
            return (0);
        }
        if (abs(add[i].x - add[0].x) > piv){
            group[0][add[i].y] = 1;
        }
        if (abs(add[i].x - add[n - 1].x) > piv){
            group[0][add[i].y] = 0;
        }
    }
    
    //suppose distance will be given by |c[1][i] - c[1][j]|
    
    group[1][minus[0].y] = 0;
    for (i = 0; i < n; i++){
        if (abs(minus[i].x - minus[0].x) > piv && abs(minus[i].x - minus[n - 1].x) > piv){
            return (0);
        }
        if (abs(minus[i].x - minus[0].x) > piv){
            group[1][minus[i].y] = 1;
        }
        if (abs(minus[i].x - minus[n - 1].x) > piv){
            group[1][minus[i].y] = 0;
        }
    }
    
    a = b = 0;
    for (i = 0; i < n; i++){
        if (group[0][i] == 2 || group[1][i] == 2){
            b++;
            continue;
        }
        if (group[0][i] != group[1][i]){
            a++;
        }
    }
    
    return (a == 0 || a + b == n);
}

int main(void)
{
    int i;
    int left, right, center;
    int x, y;
    
    scanf("%d", &n);
    
    for (i = 0; i < n; i++){
        scanf("%d%d", &x, &y);
        add[i].x = x + y;
        minus[i].x = x - y;
        add[i].y = minus[i].y = i;
    }
    
    qsort(add, n, sizeof(POINT), comp);
    qsort(minus, n, sizeof(POINT), comp);
    
    left = 0;
    right = 400000;
    
    while (left != right){
        center = (left + right) / 2;
        if (canDivide(center)){
            right = center;
        }
        else {
            left = center + 1;
        }
    }
    
    printf("%d\n", right);
    
    return (0);
}