Cod sursa(job #1714496)

Utilizator Andrei1998Andrei Constantinescu Andrei1998 Data 8 iunie 2016 15:16:46
Problema Metrou4 Scor 0
Compilator cpp Status done
Runda Arhiva ICPC Marime 4.52 kb
#include <fstream>
#include <algorithm>

#define lint long long int
using namespace std;

const int NMAX = 150005;
int n;

struct Point {
    int x, y;
    int ind;

    Point(int _x = 0, int _y = 0, int _ind = 0):
        x(_x), y(_y), ind(_ind) {}
} points[NMAX];

bool operator<(const Point &a, const Point &b) {
    if (a.x != b.x)
        return a.x < b.x;
    return a.y < b.y;
}

void reflect() {
    for (int i = 1; i <= n; ++ i)
        points[i].x = -points[i].x;
}

void rotate() {
    for (int i = 1; i <= n; ++ i) {
        int old_x = points[i].x;
        int old_y = points[i].y;

        points[i].x = -old_y;
        points[i].y =  old_x;
    }
}

struct Node {
    int st, dr;

    int best;
    int ind_best;

    Node *left, *right;

    Node(int _st = 0, int _dr = 0, int _best = 0, int _ind_best = 0, Node *_left = NULL, Node *_right = NULL):
        st(_st), dr(_dr), best(_best), ind_best(_ind_best), left(_left), right(_right) {}

    ~Node() {
        if (left != NULL)
            delete left;
        if (right != NULL)
            delete right;
    }

    void add_point(const Point &p) {
        if (!ind_best || p.x + p.y > best)
            best = p.x + p.y, ind_best = p.ind;
    }
} *root;

void update(Node *node, int where, const Point &p) {
    node -> add_point(p);

    if (node -> st == node -> dr)
        return ;

    int mid = (node -> st + node -> dr) >> 1;

    if (where <= mid) {
        if (node -> left == NULL)
            node -> left = new Node(node -> st, mid);
        update(node -> left, where, p);
    }
    else {
        if (node -> right == NULL)
            node -> right = new Node(mid + 1, node -> dr);
        update(node -> right, where, p);
    }
}

pair <int, int> query(Node *node, int where) {
    if (node -> dr == where)
        return make_pair(node -> best, node -> ind_best);

    int mid = (node -> st + node -> dr) >> 1;

    pair <int, int> ans = make_pair(0, 0);
    if (where <= mid) {
        if (node -> left != NULL)
            ans = query(node -> left, where);
    }
    else {
        pair <int, int> aux;
        if (node -> left != NULL) {
             aux = query(node -> left, mid);
            if (!ans.second || (aux.second && aux.first > ans.first))
                ans = aux;
        }

        if (node -> right != NULL) {
            aux = query(node -> right, where);
            if (!ans.second || (aux.second && aux.first > ans.first))
                ans = aux;
        }
    }

    return ans;
}

int father[NMAX];
int h[NMAX];

void init() {
    for (int i = 1; i <= n; ++ i)
        father[i] = i, h[i] = 0;
}

int find(int node) {
    if (father[node] != father[father[node]])
        father[node] = find(father[node]);
    return father[node];
}

bool unite(int a, int b) {
    a = find(a), b = find(b);

    if (a == b)
        return false;

    if (h[a] < h[b])
        father[a] = b;
    else {
        if (h[a] == h[b])
            ++ h[a];
        father[b] = a;
    }

    return true;
}

int m;
struct Edge {
    int a, b, c;

    Edge(int _a = 0, int _b = 0, int _c = 0): a(_a), b(_b), c(_c) {}
} edges[8 * NMAX];

bool operator<(const Edge &a, const Edge &b) {
    return a.c < b.c;
}

void sweep() {
    sort(points + 1, points + n + 1);
    root = new Node(-1000000000, 1000000000);

    pair <int, int> aux;
    for (int i = 1; i <= n; ++ i) {
        aux = query(root, points[i].y - points[i].x);
        if (aux.second)
            edges[++ m] = Edge(points[i].ind, aux.second, points[i].x + points[i].y - aux.first);
        update(root, points[i].y - points[i].x, points[i]);
    }

    delete root;
}

void get_edges() {
    m = 0;

    for (int k = 0; k < 2; ++ k) {
        for (int i = 0; i < 4; ++ i) {
            sweep();
            rotate();
        }
        reflect();
    }
}

lint kruskal() {
    sort(edges + 1, edges + m + 1);
    init();

    lint ans = 0;
    for (int i = 1; i <= m; ++ i)
        if (unite(edges[i].a, edges[i].b))
            ans += edges[i].c;

    return ans;
}

int main()
{
    ifstream cin("metrou4.in");
    ofstream cout("metrou4.out");

    int t = 1;
    cin >> t;

    while (t --) {
        cin >> n;
        for (int i = 1; i <= n; ++ i) {
            cin >> points[i].x >> points[i].y;
            points[i].ind = i;
        }

        get_edges();
        cout << kruskal() << '\n';
    }

    cin.close();
    cout.close();
    return 0;
}