Pagini recente » Cod sursa (job #492649) | Cod sursa (job #3212938) | Cod sursa (job #3215030) | Cod sursa (job #2751266) | Cod sursa (job #1708792)
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.logging.Level;
import java.util.logging.Logger;
/*
* @author Radu Iacob
*/
public class Main {
static String INPUT_FILE = "metrou4.in";
static String OUTPUT_FILE = "metrou4.out";
static final Integer NMAX = 150020;
static final Integer TMAX = 12;
static final Integer XMAX = 1000000000;
static int T, N;
static ArrayList<Point> points = new ArrayList<>();
static ArrayList<Edge> edges = new ArrayList<>();
static int active_lines[] = new int[NMAX];
static AIB tree = new AIB(NMAX);
static int dset[] = new int[NMAX];
static int rank[] = new int[NMAX];
static class Point implements Comparable<Point> {
public int x, y, idx;
Point(int x, int y, int idx) {
this.x = x;
this.y = y;
this.idx = idx;
}
void reflect_x() {
x = -x;
}
void reflect_y() {
y = -y;
}
void reflect_diagonal() {
int tmp = x;
x = y;
y = tmp;
}
@Override
public int compareTo(Point other) {
if (y == other.y) return x - other.x;
return other.y - y;
}
}
static public int distance(Point p1, Point p2) {
return Math.abs(p1.x - p2.x) + Math.abs(p1.y - p2.y);
}
static class Edge implements Comparable<Edge>{
public int node1, node2, cost;
Edge(int node1, int node2, int cost) {
this.node1 = node1;
this.node2 = node2;
this.cost = cost;
}
@Override
public int compareTo(Edge other) {
return cost - other.cost;
}
}
static class AIB {
int line[];
int idx[];
int size;
AIB(int size) {
line = new int[size];
idx = new int[size];
this.size = size;
}
void reset(int size) {
this.size = size;
Arrays.fill(line, 0, size + 1, Integer.MAX_VALUE);
Arrays.fill(idx, 0, size + 1, -1);
}
// position of the first 1 from the binary representation of 'it'
int zeros(int it) {
return (it ^ (it - 1)) & it;
}
// get the nearest neighbour, from the set of candidates [0 .. it]
int get(int it) {
int result_line = Integer.MAX_VALUE;
int result_idx = -1;
for (; it > 0; it -= zeros(it)) {
if (line[it] < result_line) {
result_line = line[it];
result_idx = idx[it];
}
}
return result_idx;
}
// update information about the nearest neighbour
void update(int it, Point p, int p_idx) {
int p_line = p.y - p.x;
for(; it <= size; it += zeros(it)) {
if (line[it] > p_line) {
line[it] = p_line;
idx[it] = p_idx;
}
}
}
}
static void add_edges() {
// sort points so that we traverse them in a zig-zag pattern
// from the upper-left corner
Collections.sort(points);
// an 'active set' of nearest-neighbour candidates only needs to
// account for the number of unique individual lines going north-west to south-east
int lines_count = points.size();
for (int i = 0; i < lines_count; ++i) {
active_lines[i] = points.get(i).x + points.get(i).y;
}
Arrays.sort(active_lines, 0, lines_count);
// strip duplicate lines
int idx = 0;
for (int i = 1; i < lines_count; ++i) {
if (active_lines[i] == active_lines[idx]) {
continue;
}
active_lines[++idx] = active_lines[i];
}
lines_count = idx;
tree.reset(lines_count + 1);
for (int i = 0; i < points.size(); ++i) {
Point p = points.get(i);
int key = p.x + p.y;
int line = Arrays.binarySearch(active_lines, 0, lines_count + 1, key);
int nearest_neighbour = tree.get(line + 1);
if (nearest_neighbour != -1) {
Point neighbour = points.get(nearest_neighbour);
edges.add(new Edge(p.idx, neighbour.idx, distance(p, neighbour)));
}
tree.update(line + 1, p, i);
}
}
static void build_graph() {
// consider the octal partition of the 2d space:
// 1 2
// 0 3
// 7 4
// 6 5
// relative to each point, we try to compute the closest neighbour
// in section '0'. Next, we rotate the plan, so that we can apply
// the same reasoning for each section.
for (int x = 0; x < 2; ++x) {
for (int y = 0; y < 2; ++y) {
for (int diag = 0; diag < 2; ++diag) {
add_edges();
for (Point p : points) { p.reflect_diagonal(); }
}
for (Point p : points) { p.reflect_y(); }
}
for (Point p : points) { p.reflect_x(); }
}
}
static int find(int node) {
if (node != dset[node]) {
dset[node] = find(dset[node]);
}
return dset[node];
}
static boolean unite(int node1, int node2) {
int root1 = find(node1);
int root2 = find(node2);
if (root1 == root2) {
return false;
}
if (rank[root1] > rank[root2]) {
dset[root2] = root1;
rank[root1] += rank[root2];
} else {
dset[root1] = root2;
rank[root2] += rank[root1];
}
return true;
}
static long compute_mst_cost() {
int N = points.size();
Arrays.fill(rank, 1);
for (int i = 0; i < N; ++i) {
dset[i] = i;
}
Collections.sort(edges);
long mst_cost = 0;
for (Edge edge : edges) {
int node1 = edge.node1;
int node2 = edge.node2;
if (unite(node1, node2)) {
mst_cost += (long) edge.cost;
}
}
return mst_cost;
}
static public void solve() {
try (BufferedReader br = new BufferedReader((new FileReader(INPUT_FILE)));
PrintWriter writer = new PrintWriter(OUTPUT_FILE);) {
T = Integer.parseInt(br.readLine());
while (T-- > 0) {
points.clear();
edges.clear();
N = Integer.parseInt(br.readLine());
for (int i = 0; i < N; ++i) {
int X, Y;
String[] params = br.readLine().split(" ");
X = Integer.parseInt(params[0]);
Y = Integer.parseInt(params[1]);
points.add(new Point(X, Y, i));
}
build_graph();
for (int i = 0; i < N; ++i) {
Point tmp = points.get(i);
points.set(i, points.get(tmp.idx));
points.set(tmp.idx, tmp);
}
long ans = compute_mst_cost();
writer.write(String.valueOf(ans) + "\n");
}
} catch (IOException ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
}
}
public static void main(String... args) {
solve();
}
}