# | 제출 시각 | 아이디 | 문제 | 언어 | 결과 | 실행 시간 | 메모리 |
---|---|---|---|---|---|---|---|
230659 | Giantpizzahead | ČVENK (COI15_cvenk) | Java | 0 ms | 0 KiB |
이 제출은 이전 버전의 oj.uz에서 채점하였습니다. 현재는 제출 당시와는 다른 서버에서 채점을 하기 때문에, 다시 제출하면 결과가 달라질 수도 있습니다.
/*
Solution: The labyrinth is a tree! So, do your standard shortest # of steps to meet up thing on this
tree. Find the midpoint of the people, and calculate the # of steps needed to move there.
*/
import java.io.*;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.StringTokenizer;
public class cvenkOld {
int N;
Point[] people;
Node root = new Node(0, 0);
class Node {
Node left, right;
int x, y, numPeople = 0, numPeopleST = 0;
Node(int x, int y) {
this.x = x;
this.y = y;
}
}
cvenkOld(BufferedReader in, PrintWriter out) throws IOException {
StringTokenizer st = new StringTokenizer(in.readLine());
N = Integer.parseInt(st.nextToken());
people = new Point[N];
int x, y;
for (int i = 0; i < N; i++) {
st = new StringTokenizer(in.readLine());
y = Integer.parseInt(st.nextToken());
x = Integer.parseInt(st.nextToken());
people[i] = new Point(x, y);
}
// Heuristic
Arrays.sort(people, Comparator.comparingInt(p -> -Math.abs(p.x - p.y)));
for (Point p : people) genNodes(root, p.x, p.y, 0, 0);
// Now do generic algorithm
dfs(root, 0);
answer = distSum;
findMid(root, 0);
out.println(answer);
}
long answer;
void findMid(Node n, long dist) {
// System.out.println("n = " + n + ", numInST = " + numInST + ", dist = " + dist);
int left = (n.left == null) ? 0 : n.left.numPeopleST;
int right = (n.right == null) ? 0 : n.right.numPeopleST;
if (left == right) {
// Midpoint is here!
// System.out.println("midpoint " + n);
return;
}
if (left > N / 2) {
// Go to left
answer -= (2 * left - N) * calcDist(n, n.left);
findMid(n.left, dist + calcDist(n, n.left));
} else if (right > N / 2) {
// Go to right
answer -= (2 * right - N) * calcDist(n, n.right);
findMid(n.right, dist + calcDist(n, n.right));
} else {
// Midpoint is here!
// System.out.println("midpoint " + n);
return;
}
}
long distSum = 0;
void dfs(Node n, long dist) {
n.numPeopleST += n.numPeople;
distSum += dist * n.numPeople;
if (n.left != null) {
dfs(n.left, dist + calcDist(n, n.left));
n.numPeopleST += n.left.numPeopleST;
}
if (n.right != null) {
dfs(n.right, dist + calcDist(n, n.right));
n.numPeopleST += n.right.numPeopleST;
}
}
long calcDist(Node a, Node b) {
return Math.abs(a.x - b.x) + Math.abs(a.y - b.y);
}
void genNodes(Node n, int x, int y, int offsetX, int offsetY) {
// System.out.println(n);
if (x == 0 && y == 0) n.numPeople++;
else if (x < y) {
// On left side; find how far to go down
int dist = Integer.highestOneBit(y);
y -= dist;
offsetY += dist;
while (n.left != null && n.left.y < offsetY) {
n = n.left;
}
if (n.left == null || n.left.y > offsetY) {
// Make closer node
Node temp = new Node(offsetX, offsetY);
// numNodes++;
temp.left = n.left;
n.left = temp;
}
// Continue genning nodes
genNodes(n.left, x, y, offsetX, offsetY);
} else {
// On right side
int dist = Integer.highestOneBit(x);
x -= dist;
offsetX += dist;
while (n.right != null && n.right.x < offsetX) {
n = n.right;
}
if (n.right == null || n.right.x > offsetX) {
// Make closer node
Node temp = new Node(offsetX, offsetY);
// numNodes++;
temp.right = n.right;
n.right = temp;
}
// Continue genning nodes
genNodes(n.right, x, y, offsetX, offsetY);
}
}
class Point {
int x, y;
Point(int x, int y) {
this.x = x;
this.y = y;
}
}
public static void main(String[] args) throws IOException {
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
PrintWriter out = new PrintWriter(new BufferedOutputStream(System.out));
new cvenkOld(in, out);
in.close();
out.close();
}
}