Cod sursa(job #1774891)

Utilizator depevladVlad Dumitru-Popescu depevlad Data 9 octombrie 2016 16:16:58
Problema Metrou4 Scor 0
Compilator cpp Status done
Runda Arhiva ICPC Marime 5.08 kb
#include <bits/stdc++.h>

using namespace std;

const int kMaxN = 150005;
const int kSize = 1 << 17;

struct Point {
    int x;
    int y;
    int i;
};

int n, cursor;
int f[kMaxN];
int v[kMaxN][8];
Point p[kMaxN];
char buffer[kSize];

void startParser() {
    cursor = 0;
    fread(buffer, kSize, 1, stdin);
}

inline void advanceCursor() {
    cursor++;
    if (cursor == kSize) {
        cursor = 0;
        fread(buffer, kSize, 1, stdin);
    }
}

inline void readInt(int &readTarget) {
    readTarget = 0;
    while (buffer[cursor] < '0' || '9' < buffer[cursor]) {
        advanceCursor();
    }
    while ('0' <= buffer[cursor] && buffer[cursor] <= '9') {
        readTarget = (readTarget << 1) + (readTarget << 3) + buffer[cursor] - '0';
        advanceCursor();
    }
}

int manhattanDistance(const Point &u, const Point &v) {
    return abs(u.x - v.x) + abs(u.y - v.y);
}

vector <Point> getOctant(const int id, const int lo, const int hi) {
    if (lo < hi) {
        const int med = (lo + hi) >> 1;
        vector <Point> d = getOctant(id, lo, med);
        vector <Point> u = getOctant(id, med + 1, hi);
        if (d.size() > 0 && u.size() > 0) {
            int j = 0, best = 0;
            for (int i = 0; i < d.size(); i++) {
                if (d[i].x + d[i].y >= u[0].x +  u[0].y) {
                    while (j < u.size() - 1 && u[j + 1].x + u[j + 1].y <= d[i].x + d[i].y) {
                        j++;
                        if (u[best].x - u[best].y < u[j].x - u[j].y) {
                            best = j;
                        }
                    }
                    if (v[d[i].i][id] == 0 || p[v[d[i].i][id]].x - p[v[d[i].i][id]].y < u[best].x - u[best].y) {
                        v[d[i].i][id] = u[best].i;
                    }
                }
            }
        }
        vector <Point> sorted(d.size() + u.size());
        merge(d.begin(), d.end(), u.begin(), u.end(), sorted.begin(), [] (const Point &u, const Point &v) { return u.x + u.y < v.x + v.y; });
        return sorted;
    }
    else {
        if (lo == hi) return vector <Point> (1, p[lo]);
        else return vector <Point> ();
    }
}

void solveOctants() {
    sort(p + 1, p + n + 1, [] (const Point &u, const Point &v) { return u.y < v.y; });
    for (int i = 0; i < 8; i++) {
        getOctant(i, 1, n);
        if (i & 1) {
            for (int j = 1; j <= n; j++) {
                p[j].x *= -1;
            }
        }
        else {
            for (int j = 1; j <= n; j++) {
                swap(p[j].x, p[j].y);
            }
        }
    }
}

void setStart() {
    srand(time(NULL));
    for (int i = 1; i <= n; i++) {
        f[i] = i;
    }
}

int setFind(const int u) {
    return (u == f[u] ? u: (f[u] = setFind(f[u])));
}

bool setMerge(const int u, const int v) {
    int fu = setFind(u);
    int fv = setFind(v);
    if (fu != fv) {
        if (rand() & 1) {
            swap(fu, fv);
        }
        f[fu] = fv;
        return true;
    }
    else return false;
}

vector <pair <int, int>> findEdges() {
    solveOctants();
    vector <pair <int, int>> mstEdges;
    for (int i = 1; i <= n; i++) {
        for (int j = 0; j < 8; j++) {
            if (v[i][j] != 0) {
                mstEdges.emplace_back(i, v[i][j]);
            }
        }
    }
    return mstEdges;
}

int64_t getMst() {
    vector <pair <int, int>> mstEdges = findEdges();
    sort(mstEdges.begin(), mstEdges.end(), [] (const pair <int, int> &u, const pair <int, int> &v) { 
         return manhattanDistance(p[u.first], p[u.second]) < manhattanDistance(p[v.first], p[v.second]); });
    setStart();
    int64_t mstCost = 0;
    for (const pair <int, int> &e: mstEdges) {
        const int u = e.first;
        const int v = e.second;
        if (setMerge(u, v) == true) {
            mstCost += manhattanDistance(p[u], p[v]);
        }
    }
    return mstCost;
}

int64_t bruteForceMst() {
    vector <pair <int, int>> mstEdges;
    for (int i = 1; i <= n; i++) {
        for (int j = i + 1; j <= n; j++) {
            mstEdges.emplace_back(i, j);
        }
    }
    sort(mstEdges.begin(), mstEdges.end(), [] (const pair <int, int> &u, const pair <int, int> &v) { 
        return manhattanDistance(p[u.first], p[u.second]) < manhattanDistance(p[v.first], p[v.second]);
    });
    setStart();
    int64_t mstCost = 0;
    for (const pair <int, int> &e: mstEdges) {
        const int u = e.first;
        const int v = e.second;
        if (setMerge(u, v) == true) {
            mstCost += manhattanDistance(p[u], p[v]);
        }
    }
    return mstCost;
}

int main() {
    freopen("metrou4.in", "r", stdin);
    freopen("metrou4.out", "w", stdout);
    
    startParser();
    
    int testCases;
    for (readInt(testCases); testCases > 0; testCases--) {
        memset(v, 0, sizeof v);
        readInt(n);
        for (int i = 1; i <= n; i++) {
            readInt(p[i].x);
            readInt(p[i].y);
            p[i].i = i;
        }
        printf("%lld\n", getMst());
    }
    
    return 0;
}