Problem:
MathJax.Hub.Config({ tex2jax: { inlineMath: [["$","$"], ["\\(","\\)"]], processEscapes: true }});

Segment Intersections: Manhattan Geometry

For given $n$ segments which are parallel to X-axis or Y-axis, find the number of intersections of them.

Input

In the first line, the number of segments $n$ is given. In the following $n$ lines, the $i$-th segment is given by coordinates of its end points in the following format:

$x_1 \; y_1 \; x_2 \; y_2$

The coordinates are given in integers.

Output

Print the number of intersections in a line.

Constraints

$1 \leq n \leq 100,000$

$ -1,000,000,000 \leq x_1, y_1, x_2, y_2 \leq 1,000,000,000$

Two parallel segments never overlap or touch.

The number of intersections $\leq 1,000,000$

Sample Input 1

6
2 2 2 5
1 3 5 3
4 1 4 4
5 2 7 2
6 1 6 3
6 5 6 7

Sample Output 1

3

Solution in Scala (judge verdict: Accepted)

import scala.collection.mutable
import scala.collection.mutable.ArrayBuffer
import scala.io.StdIn

object Main {

  case class Point(x: Double = 0, y: Double = 0) {

    def +(p: Point): Point = Point(this.x + p.x, this.y + p.y)

    def -(p: Point): Point = Point(this.x - p.x, this.y - p.y)

    def *(a: Double): Point = Point(this.x * a, this.y * a)

    def /(a: Double): Point = {
      assert(a != 0)
      Point(this.x / a, this.y / a)
    }

    def norm(): Double = this.x * this.x + this.y * this.y

    def abs(): Double = scala.math.sqrt(norm())

    def <(p: Point): Boolean = this.x < p.x && this.y < p.y


    def ==(p: Point): Boolean = scala.math.abs(this.x - p.x) < Cgl0A.EPS &&
      scala.math.abs(this.y - p.y) < Cgl0A.EPS


  }

  case class Circle(center: Point, r: Int)

  case class Segment(p1: Point, p2: Point)

  case class Line(p1: Point, p2: Point)

  type GeoVector = Point

  object Cgl0A {
    val EPS: Double = scala.math.pow(10, -10)

    // 内積
    def dot(a: Point, b: Point): Double = a.x * b.x + a.y * b.y

    def isOrthogonal(a: GeoVector, b: GeoVector): Boolean = dot(a, b) == 0.0

    def isOrthogonal(a1: Point, a2: Point, b1: Point, b2: Point): Boolean = {
      isOrthogonal(a1 - a2, b1 - b2)
    }

    def isOrthogonal(s1: Segment, s2: Segment): Boolean = {
      dot(s1.p2 - s1.p1, s2.p2 - s2.p1) == 0.0
    }

    // 外積
    def cross(a: Point, b: Point): Double = a.x * b.y - a.y * b.x

    def isParallel(a: GeoVector, b: GeoVector): Boolean = cross(a, b) == 0.0

    def isParallel(a1: Point, a2: Point, b1: Point, b2: Point): Boolean = {
      isParallel(a1 - a2, b1 - b2)
    }

    def isParallel(s1: Segment, s2: Segment): Boolean = {
      cross(s1.p2 - s1.p1, s2.p2 - s2.p1) == 0.0
    }

    def project(s: Segment, p: Point): Point = {
      val base: GeoVector = s.p2 - s.p1
      val r: Double = Cgl0A.dot(p - s.p1, base) / base.norm()
      s.p1 + base * r
    }

    def reflect(s: Segment, p: Point): Point = {
      p + (project(s, p) - p) * 2.0
    }

    def getDistance(a: Point, b: Point): Double = (a - b).abs()

    def getDistanceLP(l: Line, a: Point): Double = {
      scala.math.abs(cross(l.p2 - l.p1, a - l.p1) / (l.p2 - l.p1).abs())
    }

    def getDistanceSP(s: Segment, a: Point): Double = {
      if (dot(s.p2 - s.p1, a - s.p1) < 0.0) (a - s.p1).abs()
      else if (dot(s.p1 - s.p2, a - s.p2) < 0.0) (a - s.p2).abs()
      else getDistanceLP(Line(s.p1, s.p2), a)
    }

    def getDistance(s1: Segment, s2: Segment): Double = {
      if (intersect(s1, s2)) {
        0.0
      }
      else {
        math.min(math.min(getDistanceSP(s1, s2.p1), getDistanceSP(s1, s2.p2)),
          math.min(getDistanceSP(s2, s1.p1), getDistanceSP(s2, s1.p2)))
      }
    }

    val COUNTER_CLOCKWISE: Int = 1
    val CLOCKWISE: Int = -1
    val ONLINE_BACK: Int = 2
    val ONLINE_FRONT: Int = -2
    val ON_SEGMENT: Int = 0

    def ccw(p0: Point, p1: Point, p2: Point): Int = {
      val a: GeoVector = p1 - p0
      val b: GeoVector = p2 - p0

      if (cross(a, b) > EPS) COUNTER_CLOCKWISE
      else if (cross(a, b) < -1 * EPS) CLOCKWISE
      else if (dot(a, b) < -1 * EPS) ONLINE_BACK
      else if (a.norm() < b.norm()) ONLINE_FRONT
      else ON_SEGMENT

    }

    def intersect(p1: Point, p2: Point, p3: Point, p4: Point): Boolean = {
      Cgl0A.ccw(p1, p2, p3) * Cgl0A.ccw(p1, p2, p4) <= 0 &&
        Cgl0A.ccw(p3, p4, p1) * Cgl0A.ccw(p3, p4, p2) <= 0
    }

    def intersect(s1: Segment, s2: Segment): Boolean = {
      Cgl0A.intersect(s1.p1, s1.p2, s2.p1, s2.p2)
    }

    def getCrossPoint(s1: Segment, s2: Segment): Point = {
      val base: GeoVector = s2.p2 - s2.p1
      val d1 = scala.math.abs(cross(base, s1.p1 - s2.p2))
      val d2 = scala.math.abs(cross(base, s1.p2 - s2.p1))
      val t = d1 / (d1 + d2)
      s1.p1 + (s1.p2 - s1.p1) * t
    }

    def getCrossPoint(c: Circle, l: Line): Array[Point] = {
      val pr: GeoVector = project(Segment(l.p1, l.p2), c.center)
      val e: GeoVector = (l.p2 - l.p1) / (l.p2 - l.p1).abs()
      val base: Double = scala.math.sqrt(c.r * c.r - (pr - c.center).norm())
      Array(pr + e * base, pr - e * base).sortBy(p => (p.x, p.y))
    }

    // arq tangent
    def arg(p: GeoVector): Double = scala.math.atan2(p.y, p.x)

    // 
    def polar(a: Double, r: Double): GeoVector = {
      // x * 角度ラジアン
      Point(scala.math.cos(r) * a, scala.math.sin(r) * a)
    }

    def getCrossPoint(c1: Circle, c2: Circle): Array[Point] = {
      val d: Double = (c1.center - c2.center).abs()
      val cos: Double = (c1.r * c1.r + d * d - c2.r * c2.r) / (2 * c1.r * d)
      val a: Double = scala.math.acos(cos) // radian

      val t: Double = arg(c2.center - c1.center) // radian
      Array(c1.center + polar(c1.r, t + a),
        c1.center + polar(c1.r, t - a)).sortBy(p => (p.x, p.y))

    }

    val IN: Int = 2
    val ON: Int = 1
    val OUT: Int = 0

    def contains(g: IndexedSeq[Point], target: Point): Int = {
      val n = g.size
      var i = 0
      var onJudge = false
      var parity = false
      while (!onJudge && i < n) {
        var a: Point = g(i) - target
        var b: Point = g((i + 1) % n) - target
        if (cross(a, b).abs < EPS && dot(a, b) < EPS) {
          onJudge = true
        } else {
          if (a.y > b.y) {
            val temp = a
            a = b
            b = temp
          }
          parity = if (a.y < EPS && EPS < b.y && cross(a, b) > EPS) !parity else parity
        }
        i += 1
      }

      if (onJudge) {
        ON
      } else {
        if (parity) IN else OUT
      }
    }


    def andrewScan(s: Array[Point]): Array[Point] = {
      val u: ArrayBuffer[Point] = ArrayBuffer.empty[Point]
      val l: ArrayBuffer[Point] = ArrayBuffer.empty[Point]

      val sSize = s.length
      if (sSize < 3) {
        s
      } else {
        val temp = s.sortBy(p => (p.y, p.x))
        u.append(temp(0))
        u.append(temp(1))

        l.append(temp(sSize - 1))
        l.append(temp(sSize - 2))

        (2 until sSize).foreach { i =>
          var n = u.size
          while (n >= 2 && ccw(u(n - 2), u(n - 1), temp(i)) == COUNTER_CLOCKWISE) {
            u.remove(n - 1)
            n -= 1
          }
          u.append(temp(i))
        }

        (sSize - 3 to 0 by -1).foreach { i =>
          var n = l.size
          while (n >= 2 && ccw(l(n - 2), l(n - 1), temp(i)) == COUNTER_CLOCKWISE) {
            l.remove(n - 1)
            n -= 1
          }
          l.append(temp(i))
        }

        //println("U: " + u.toList)
        //println("L: " + l.toList)

        val r: ArrayBuffer[Point] = l.reverse
        u.reverse.slice(1, u.size - 1).foreach(e => r.append(e))

        r.toArray
      }

    }

    def manhattanIntersection(s: Array[Segment]): Int = {

      val BOTTOM = 0
      val LEFT = 1
      val RIGHT = 2
      val TOP = 3

      case class EndPoint(p: Point, id: Int, place: Int)

      var ep: ArrayBuffer[EndPoint] = ArrayBuffer.empty[EndPoint]

      def swapJudge(p1: Point, p2: Point): Boolean = {
        p1.y == p2.y && p1.x > p2.x || p1.y > p2.y
      }


      val n = s.length
      (0 until n).foreach { i =>
        s(i) = if (swapJudge(s(i).p1, s(i).p2)) {
          Segment(s(i).p2, s(i).p1)
        } else {
          s(i)
        }
        
        if (s(i).p1.y == s(i).p2.y) {
          ep.append(EndPoint(s(i).p1, i, LEFT))
          ep.append(EndPoint(s(i).p2, i, RIGHT))
        } else {
          ep.append(EndPoint(s(i).p1, i, BOTTOM))
          ep.append(EndPoint(s(i).p2, i, TOP))
        }
      }

      ep = ep.sortBy(e => (e.p.y, e.place))

      val trset: mutable.TreeSet[Double] = mutable.TreeSet.empty[Double]
      
      //println(ep.toList)

      ep.foldLeft(0) { (acc, e) =>
        //println(trset.toList)
        if (e.place == TOP) {
          trset.remove(e.p.x)
          acc
        } else if (e.place == BOTTOM) {
          trset.add(e.p.x)
          acc
        } else if (e.place == LEFT) {
          val r = trset.range(s(e.id).p1.x-0.1, s(e.id).p2.x+0.1)
          //println("match:" + r.toList)

          acc + r.size
        } else acc
      }
    }
  }


  def main(args: Array[String]): Unit = {
    val n = StdIn.readLine().toInt
    
    val lines = (0 until n).map { _ =>
      val points = StdIn.readLine().split(' ').map(_.toInt)
      Segment(Point(points(0), points(1)), Point(points(2), points(3)))
    }.toArray

    val r = Cgl0A.manhattanIntersection(lines)
    println(r)

  }

}