Cod sursa(job #2422219)

Utilizator NOSCOPEPROKENDYMACHEAMACUMVREAU NOSCOPEPROKENDY Data 17 mai 2019 21:34:14
Problema Metrou4 Scor 100
Compilator cpp-64 Status done
Runda Arhiva ICPC Marime 3.97 kb
#include <fstream>

//#include <iostream>

#include <vector>

#include <algorithm>

#include <cstring>

 

using namespace std;

 

ifstream cin("metrou4.in");

ofstream cout("metrou4.out");

 

const int MAXN = 150000;

 

struct Point {

    int x, y;

    int index;

 

    bool operator < (const Point &other) const {

        if (x == other.x)

            return y < other.y;

        return x < other.x;

    }

};

 

Point v[1 + MAXN];

 

struct Edge {

    int from, to;

    int cost;

 

    bool operator < (const Edge &other) const {

        return cost < other.cost;

    }

};

 

vector<Edge> edges;

 

void Rotate(int n) {

    for (int i = 1; i <= n; i++) {

        int x = v[i].x, y = v[i].y;

        v[i].x = -y;

        v[i].y = x;

    }

}

 

void Reflect(int n) {

    for (int i = 1; i <= n; i++)

        v[i].x *= -1;

}

 

int number[1 + MAXN];

pair<int, int> tree[1 + 4 * MAXN];

 

void Update(int node, int left, int right, int where, const Point &point) {

    if (!tree[node].second || tree[node].first < point.x + point.y)

        tree[node] = make_pair(point.x + point.y, point.index);

    if (left == right)

        return;

    int middle = (left + right) / 2;

    if (where <= middle)

        Update(2 * node, left, middle, where, point);

    else

        Update(2 * node + 1, middle + 1, right, where, point);

}

 

pair<int, int> Query(int node, int left, int right, int limit) {

    if (right <= limit)

        return tree[node];

    int middle = (left + right) / 2;

    if (limit <= middle)

        return Query(2 * node, left, middle, limit);

    pair<int, int> answer = Query(2 * node, left, middle, limit), temp = Query(2 * node + 1, middle + 1, right, limit);

    if (!answer.second || (temp.second && answer.first < temp.first))

        answer = temp;

    return answer;

}

 

void GetEdges(int n) {

    for (int i = 1; i <= n; i++)

        number[i] = v[i].y - v[i].x;

    sort(number + 1, number + n + 1);

    sort(v + 1, v + n + 1);

    int m = unique(number + 1, number + n + 1) - number - 1;

    for (int i = 1; i <= 4 * n; i++)

        tree[i] = make_pair(0, 0);

    for (int i = 1; i <= n; i++) {

        int where = lower_bound(number + 1, number + m + 1, v[i].y - v[i].x) - number;

        pair<int, int> answer = Query(1, 1, m, where);

        if (answer.second)

            edges.push_back({v[i].index, answer.second, v[i].x + v[i].y - answer.first});

        Update(1, 1, m, where, v[i]);

    }

}

 

int dad[1 + MAXN], h[1 + MAXN];

 

void Initialize(int n) {

    for (int i = 1; i <= n; i++) {

        dad[i] = i;

        h[i] = 1;

    }

}

 

int FindDad(int node) {

    if (dad[node] == node)

        return node;

    return dad[node] = FindDad(dad[node]);

}

 

void Join(int a, int b) {

    if (h[a] < h[b])

        dad[a] = b;

    else {

        dad[b] = a;

        if (h[a] == h[b])

            h[a]++;

    }

}

 

int main() {

    int tests;

    cin >> tests;

    for (int test = 1; test <= tests; test++) {

        int n;

        cin >> n;

        for (int i = 1; i <= n; i++) {

            cin >> v[i].x >> v[i].y;

            v[i].index = i;

        }

        edges.clear();

        for (int i = 1; i <= 2; i++) {

            for (int j = 1; j <= 4; j++) {

                GetEdges(n);

                Rotate(n);

            }

            Reflect(n);

        }

        Initialize(n);

        sort(edges.begin(), edges.end());

        long long answer = 0;

        for (auto &edge : edges)

            if (FindDad(edge.from) != FindDad(edge.to)) {

                answer += edge.cost;

                Join(FindDad(edge.from), FindDad(edge.to));

            }

        cout << answer << "\n";

    }

    return 0;

}