Cod sursa(job #1925630)

Utilizator fanache99Constantin-Buliga Stefan fanache99 Data 13 martie 2017 14:58:27
Problema Metrou4 Scor 100
Compilator cpp Status done
Runda Arhiva ICPC Marime 3.67 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;
}