Problem:
問題 ４

　平面上の n 個の点 P1, ..., Pn が与えられたとき，
距離が最小の２点を求めたい．

　入力ファイルの１行目には整数 n が書いてある．
２行目から n+1 行目のそれぞれには，
２つの正整数 x, y が１つの半角空白文字を区切りとして書いてある．
i+1 行目の x, y はそれぞれ Pi の x 座標，
Pi の y 座標である．
これら n 点の中から最も近い２点を選んだとき，
この２点間の距離の２乗を出力せよ．

　ただし，
2≤n≤500000 かつ -10000≤x≤10000, -10000≤y≤10000 とし，
５つの入力ファイルのうち３つでは n≤100 である．
また，どの入力ファイルにおいても，全ての座標は異なるものとする．

出力ファイルにおいては，
出力の最後の行にも改行コードを入れること．

入出力例

入力例１

2
0 0
1 1

出力例１

2

入力例２

3
5 5
0 0
-3 -4

出力例２

25

問題文と自動審判に使われるデータは、情報オリンピック日本委員会が作成し公開している問題文と採点用テストデータです。

Solution in Scala (judge verdict: Accepted)


object Main extends App{
  import scala.io.StdIn._
  val n: Int = readLine.trim.toInt
  val pointsSortByX = Array.tabulate(n){_ ⇒ val Array(x, y) = readLine.trim.split(' ').map(_.toInt); Point(x, y)}.sortBy{_.x}
  val pointsSortByY = pointsSortByX.sortBy(_.y)
  pointsSortByX.zipWithIndex.foreach{case (p, i) ⇒ p.rankX = i}
  println(minDistanceSquare(pointsSortByX, pointsSortByY))
  def minDistanceSquare(pointsSortByX: Array[Point], pointsSortByY: Array[Point]): Long = {
    pointsSortByX.length match{
      case 0 ⇒ Int.MaxValue
      case 1 ⇒ Int.MaxValue
      case 2 ⇒ pointsSortByX(0).distanceSquare(pointsSortByX(1))
      case n ⇒
        val mid = pointsSortByX(n / 2)
        val leftX = Array.tabulate(n / 2){i ⇒ pointsSortByX(i)}
        val leftY = pointsSortByY.filter{_.rankX < n / 2}
        val leftMin = minDistanceSquare(leftX, leftY)
        val rightX = Array.tabulate(n - n / 2 - 1){i ⇒ pointsSortByX(n / 2 + 1 + i)}
        val rightY = pointsSortByY.filter{_.rankX > n / 2}
        val rightMin = minDistanceSquare(rightX, rightY)
        val minHalf = if (leftMin < rightMin) leftMin else rightMin
        val suspectLeft = leftX.filter{p ⇒ mid.x - minHalf <= p.x && mid.x + minHalf >= p.x && mid.y - minHalf <= p.y && mid.y + minHalf >= p.y}
        val suspectRight = rightX.filter{p ⇒ mid.x - minHalf <= p.x && mid.x + minHalf >= p.x && mid.y - minHalf <= p.y && mid.y + minHalf >= p.y}
        val minAcross = if (suspectLeft.isEmpty || suspectRight.isEmpty) Int.MaxValue else suspectLeft.map{l ⇒ suspectRight.map{r ⇒ l.distanceSquare(r)}.min}.min
        val minMid = if (suspectLeft.isEmpty && suspectRight.isEmpty) Int.MaxValue else List(suspectLeft, suspectRight).filterNot{_.isEmpty}.flatMap{_.map{p ⇒ p.distanceSquare(mid)}}.min
        List(minMid, minAcross, minHalf).min
    }
  }
}
case class Point(x: Long, y: Long) {
  var rankX: Int = 0
  var rankY: Int = 0
  def distanceSquare(that: Point): Long = (x - that.x) * (x - that.x) + (y - that.y) * (y - that.y)

}