AOJ 0552 - Exposition

コードがやばい.

解法

(x, y) -> (x+y, x-y)という変換(45度回転)をすると,施設iと施設jの距離は
max{|x[i]-x[j]|, |y[i]-y[j]|}
と表されます.以下,変換後の座標系で話をすすめます.
まず,x座標とy座標で幅の広い方(最小値と最大値の差が大きい方.同じときはどちらでもいい)を選び,その座標の最小値と最大値を求める.
この2つが同じテーマだと,どう頑張っても最長になってしまうので違うテーマに分けてあげます.
その後,各テーマで(最小/最大)の(x座標/y座標)をもちながら,次のようにテーマを割り振る.
それぞれのテーマで最も遠い施設を求め,より距離が遠い方(同じときはどちらでもよい)を,他方のテーマに割り当てる.
すべての施設を割り当てたとき,2つのテーマの(x座標/y座標)の最小・最大の差の大きい方が答えになります.

x座標とy座標で幅の広い方,最も遠い点はどう求めたらいいでしょうか.距離の式がx座標,y座標について分離しているので,x座標でソートしたもの,y座標でソートしたものがあるといいですね.さらに,削除がある程度速いといいですね.これって何てstd::set.(なお,特別なデータ構造をつかわなくても解ける模様.)

コード

Ω\・8・)チューン

// ナニソレイミワカンナイ

#include <cstdio>
#include <vector>
#include <algorithm>
#include <set>
#include <tuple>

typedef std::pair<int,int> P;
typedef std::tuple<P,bool,int> Q;
std::set<P> setX, setY;
int N;

Q f(int mnX, int mxX, int mnY, int mxY){
    P p = *setX.begin();
    bool isX = true;
    int l = std::max(std::abs(mnX-p.first),
                     std::abs(mxX-p.first));

    P _p;
    int _l;
    _p = *setX.rbegin();
    if((_l = std::max(std::abs(mnX-_p.first),
                      std::abs(mxX-_p.first))) > l){
        p = _p;
        l = _l;
    }

    _p = *setY.begin();
    if((_l = std::max(std::abs(mnY-_p.first),
                      std::abs(mxY-_p.first))) > l){
        p = _p;
        l = _l;
        isX = false;
    }

    _p = *setY.rbegin();
    if((_l = std::max(std::abs(mnY-_p.first),
                      std::abs(mxY-_p.first))) > l){
        p = _p;
        l = _l;
        isX = false;
    }

    return std::make_tuple(p, isX, l);
}

int main(){
    scanf("%d", &N);

    for(int i=0;i<N;i++){
        int x, y;
        scanf("%d %d", &x, &y);

        int x_ = x+y, y_ = x-y;
        setX.insert(std::make_pair(x_, y_));
        setY.insert(std::make_pair(y_, x_));
    }

    int mnX1, mxX1, mnY1, mxY1,
        mnX2, mxX2, mnY2, mxY2;
    if(setX.rbegin()->first-setX.begin()->first >
       setY.rbegin()->first-setY.begin()->first){
        mnX1 = setX.begin()->first;
        mxX1 = mnX1;
        mnY1 = setX.begin()->second;
        mxY1 = mnY1;
        mnX2 = setX.rbegin()->first;
        mxX2 = mnX2;
        mnY2 = setX.rbegin()->second;
        mxY2 = mnY2;

        P p1 = *setX.begin(), p2 = *setX.rbegin();
        setY.erase(std::make_pair(p1.second, p1.first));
        setY.erase(std::make_pair(p2.second, p2.first));
        setX.erase(p1);
        setX.erase(p2);
    }else{
        mnX1 = setY.begin()->second;
        mxX1 = mnX1;
        mnY1 = setY.begin()->first;
        mxY1 = mnY1;
        mnX2 = setY.rbegin()->second;
        mxX2 = mnX2;
        mnY2 = setY.rbegin()->first;
        mxY2 = mnY2;

        P p1 = *setY.begin(), p2 = *setY.rbegin();
        setX.erase(std::make_pair(p1.second, p1.first));
        setX.erase(std::make_pair(p2.second, p2.first));
        setY.erase(p1);
        setY.erase(p2);
    }
    
    for(;!setX.empty();){
        Q q1 = f(mnX1, mxX1, mnY1, mxY1),
          q2 = f(mnX2, mxX2, mnY2, mxY2);

        if(std::get<2>(q1) > std::get<2>(q2)){
            mnX2 = std::min(mnX2, std::get<1>(q1) ? std::get<0>(q1).first : std::get<0>(q1).second);
            mxX2 = std::max(mxX2, std::get<1>(q1) ? std::get<0>(q1).first : std::get<0>(q1).second);
            mnY2 = std::min(mnY2, std::get<1>(q1) ? std::get<0>(q1).second : std::get<0>(q1).first);
            mxY2 = std::max(mxY2, std::get<1>(q1) ? std::get<0>(q1).second : std::get<0>(q1).first);

            setX.erase(std::get<1>(q1) ? std::get<0>(q1) : std::make_pair(std::get<0>(q1).second, std::get<0>(q1).first));
            setY.erase(std::get<1>(q1) ? std::make_pair(std::get<0>(q1).second, std::get<0>(q1).first) : std::get<0>(q1));
        }else{
            mnX1 = std::min(mnX1, std::get<1>(q2) ? std::get<0>(q2).first : std::get<0>(q2).second);
            mxX1 = std::max(mxX1, std::get<1>(q2) ? std::get<0>(q2).first : std::get<0>(q2).second);
            mnY1 = std::min(mnY1, std::get<1>(q2) ? std::get<0>(q2).second : std::get<0>(q2).first);
            mxY1 = std::max(mxY1, std::get<1>(q2) ? std::get<0>(q2).second : std::get<0>(q2).first);

            setX.erase(std::get<1>(q2) ? std::get<0>(q2) : std::make_pair(std::get<0>(q2).second, std::get<0>(q2).first));
            setY.erase(std::get<1>(q2) ? std::make_pair(std::get<0>(q2).second, std::get<0>(q2).first) : std::get<0>(q2));
        }
        
    printf("%d\n", std::max({mxX1-mnX1, mxY1-mnY1,
                    mxX2-mnX2, mxY2-mnY2}));
}