Cod sursa(job #1757390)

Utilizator iordache.bogdanIordache Ioan-Bogdan iordache.bogdan Data 14 septembrie 2016 22:29:48
Problema Metrou4 Scor 0
Compilator cpp Status done
Runda Arhiva ICPC Marime 4.12 kb
#include <fstream>
#include <algorithm>
#include <cstring>
#include <vector>

using namespace std;

ifstream fin("metrou4.in");
ofstream fout("metrou4.out");

const int dim = 150005;

struct Point {

	int x, y, index;
	Point(int x = 0, int y = 0, int index = 0) :
		x(x), y(y), index(index) {}
	bool operator < (const Point& obj) {
		return (x == obj.x ? y < obj.y : x < obj.x);
	}

};

struct Edge {

	int a, b, cost;
	Edge(int a = 0, int b = 0, int cost = 0) :
		a(a), b(b), cost(cost) {}
	bool operator < (const Edge& obj) {
		return cost < obj.cost;
	}

};

class SegmentTree {

private:

	int n;
	pair<int, int> nodes[4 * dim];

	void _Update(int node, int lef, int rig, int pos, const Point& point) {

		if (nodes[node].second == 0 || nodes[node].first < point.x + point.y)
			nodes[node] = make_pair(point.x + point.y, point.index);

		if (lef == rig)
			return;

		int mid = (lef + rig) / 2;
		if (pos <= mid)
			_Update(2 * node, lef, mid, pos, point);
		else
			_Update(2 * node + 1, mid + 1, rig, pos, point);

	}

	pair<int, int> _Query(int node, int lef, int rig, int pos) {

		if (rig <= pos)
			return nodes[node];

		int mid = (lef + rig) / 2;
		pair<int, int> ret(0, 0);

		if (pos <= mid)
			ret = _Query(2 * node, lef, mid, pos);
		else {

			ret = _Query(2 * node, lef, mid, pos);
			pair<int, int> aux = _Query(2 * node + 1, mid + 1, rig, pos);

			if (ret.second == 0 || (aux.second != 0 && ret.first < aux.first))
				ret = aux;

		}

		return ret;

	}

public:

	SegmentTree() {}

	void Reset(int n) {
		this->n = n;
		for (int i = 1; i <= 4 * n; ++i)
			nodes[i] = { 0, 0 };
	}

	void Update(int pos, const Point& point) {
		_Update(1, 1, n, pos, point);
	}

	pair<int, int> Query(int pos) {
		return _Query(1, 1, n, pos);
	}

};

class DisJoint {

private:

	int parent[dim];

public:

	void Reset() {
		memset(parent, -1, sizeof parent);
	}

	DisJoint() {
		Reset();
	}

	int GetRoot(int x) {

		int aux = x;
		while (parent[x] > 0)
			x = parent[x];

		int root = x;
		x = aux;
		while (x != root) {
			aux = parent[x];
			parent[x] = root;
			x = aux;
		}

		return root;

	}

	bool Join(int x, int y) {

		x = GetRoot(x);
		y = GetRoot(y);

		if (x == y)
			return false;

		if (parent[x] < parent[y]) {
			parent[x] += parent[y];
			parent[y] = x;
		}
		else {
			parent[y] += parent[x];
			parent[x] = y;
		}

		return true;

	}

};

int n;
Point points[dim];

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

void Rotate() {

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

}

SegmentTree segmentTree;
vector<int> coords;
vector<Edge> edges;

void BuildEdges() {

	coords.clear();
	for (int i = 1; i <= n; ++i)
		coords.push_back(points[i].y - points[i].x);
	sort(coords.begin(), coords.end());
	coords.erase(unique(coords.begin(), coords.end()), coords.end());

	segmentTree.Reset((int)coords.size());

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

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

		int pos = lower_bound(coords.begin(), coords.end(), points[i].y - points[i].x) - coords.begin() + 1;

		pair<int, int> ans = segmentTree.Query(pos);
		if (ans.second != 0)
			edges.push_back(Edge(points[i].index, ans.second, points[i].x + points[i].y - ans.first));

		segmentTree.Update(pos, points[i]);

	}

}

void InitEdges() {

	edges.clear();

	for (int i = 1; i <= 2; ++i) {
		for (int j = 1; j <= 4; ++j) {
			BuildEdges();
			Rotate();
		}
		Reflect();
	}

}

DisJoint disJoint;

long long Kruskal() {

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

	long long ret = 0;
	for (auto& curr : edges)
		if (disJoint.Join(curr.a, curr.b))
			ret += curr.cost;

	return ret;

}

int main() {

	int testCount;
	fin >> testCount;

	while (testCount--) {

		fin >> n;
		for (int i = 1; i <= n; ++i) {
			fin >> points[i].x >> points[i].y;
			points[i].index = i;
		}

		InitEdges();
		fout << Kruskal() << '\n';

	}

	return 0;

}

//Trust me, I'm the Doctor!