Calculate The Medians
Difficulty: Hard

<sub>*Time limits* for this challenges is two times of the [default one](https://www.hackerrank.com/environment).</sub>

The math teacher loves the concept of median very much. One day, he comes up with a question about medians and wants the students to solve it.

He provides his students with two arrays of integers, 

- $A = \{a_1, a_2, \ldots, a_n\}$
- $B = \{b_1, b_2, \ldots, b_m\}$  

, followed by $k$ queries.  
Each query consists of two ranges, $(x, y)$ and $(z, w)$ for both arrays, respectively. The students need to compute the median of a new array formed by concatenating subarrays $A[x \ldots y] = \{a_x, a_{x+1}, ... , a_y\}$ and $B[z \ldots w] = \{b_z, b_{z+1}, ... , b_w\}$.

Could you solve it by writing a computer program?

*Note*

- Indexing starts from 1.
- Median of a sorted array with
	- an odd number of elements is the middle integer.
	- an even number of elements is the average of two middle integers.

Input Format:
The first line contains two integers, $n$ and $m$, indicating lengths of the two arrays $A$ and $B$, respectively.<br>
The second line contains $n$ integers, representing the array $A$.<br>
The third line contains $m$ integers, representing the array $B$.<br>
The fourth line contains an integer $k$, indicating the number of queries.<br>
Then follows $k$ lines, each line contains four integers $x$, $y$, $z$ and $w$, as described above.

Output Format:
For each query, output the answer in a single line. 

**Constraints**

- $1 \le n, m \le 50000$
- $1 \le a_i, b_j \le 10^9\ , i \in [1, n], j \in [1, m]$
- $1 \le k \le 20000$
- $1 \le x \le y \le n$
- $1 \le z \le w \le m$
- The absolute error between your and expected output should not exceed $10^{-6}$.

Sample Input:
    5 6
    4 3 9 7 8
    1 8 3 6 5 2
    4
    1 5 1 6
    1 1 2 4
    1 2 3 4
    3 5 4 6

Sample Output:
    5.0
    5.0
    3.5
    6.5

Python 3 starter code:


Reference solution (Python):
    import scala.collection.mutable.TreeSet

    /**
     * Created by Bo You (stoundmire) on 2015/3/4.
     */
    object Solution {


      def combine(a: Array[Int], b: Array[Int]): Array[Int] = {
        val s = new TreeSet[Int]()
        for (x <- a) {
          s.add(x)
        }
        for (x <- b) {
          s.add(x)
        }
        return s.toArray
      }

      def bisearch(a: Array[Int], v: Int): Int = {
        def iter(l: Int, r: Int): Int = {
          if (l == r) {
            return l
          } else {
            val mid = (l + r) / 2
            return if (a(mid) >= v) iter(l, mid) else iter(mid + 1, r)
          }
        }
        return iter(0, a.length - 1)
      }


      class Node(val l: Int, val r: Int, val v: Int, val leftChild: Node, val rightChild: Node) {
      }

      def build(a: Array[Int], all: Array[Int]): Array[Node] = {
        val r = Array.fill[Node](a.length + 1)(null)
        // initialize an empty segment tree
        def init(): Node = {
          def iter(l: Int, r: Int): Node = {
            if (l == r) {
              return new Node(l, r, 0, null, null)
            } else {
              val mid = (l + r) / 2
              return new Node(l, r, 0, iter(l, mid), iter(mid + 1, r))
            }
          }
          return iter(0, all.length - 1)
        }
        // alter one path from root to leaf
        def process(idx: Int): Unit = {
          if (idx > a.length) {
            return
          }
          val x = bisearch(all, a(idx - 1))
          def update(node: Node): Node = {
            val l = node.l
            val r = node.r
            val v = node.v
            val mid = (l + r) / 2
            if (l == r) {
              return new Node(l, r, v + 1, null, null)
            } else if (mid >= x) {
              return new Node(l, r, v + 1, update(node.leftChild), node.rightChild)
            } else {
              return new Node(l, r, v, node.leftChild, update(node.rightChild))
            }
          }
          r(idx) = update(r(idx - 1))
          process(idx + 1)
        }
        r(0) = init()
        process(1)
        return r
      }

      def query(x: Int, root: Node): Int = {
        def iter(node: Node): Int = {
          val l = node.l
          val r = node.r
          val mid = (l + r) / 2
          if (l == r) {
            return node.v
          } else if (x > mid) {
            return node.v + iter(node.rightChild)
          } else {
            return iter(node.leftChild)
          }
        }
        return iter(root)
      }

      def solve(x: Int, y: Int, z: Int, w: Int, treeA: Array[Node], treeB: Array[Node], all: Array[Int]): Double = {
        def getValue(rank: Int, lo: Int, hi: Int): Int = {
          def getRank(v: Int): Int = {
            return query(v, treeA(y)) - query(v, treeA(x - 1)) + query(v, treeB(w)) - query(v, treeB(z - 1))
          }
          if (lo == hi) {
            return lo
          } else {
            val mid = (lo + hi) / 2
            if (getRank(mid) < rank) {
              return getValue(rank, mid + 1, hi)
            } else {
              return getValue(rank, lo, mid)
            }
          }
        }
        val cnt = y - x + 1 + w - z + 1
        if (cnt % 2 != 0) {
          return all(getValue((cnt + 1) / 2, 0, all.length - 1))
        } else {
          val m = cnt / 2
          return (all(getValue(m, 0, all.length - 1)) + all(getValue(m + 1, 0, all.length - 1))) / 2.0
        }
      }


      def main(args: Array[String]): Unit = {
        val sz = readLine.split(" ", -1).map(_.toInt)
        val a = readLine.split(" ", -1).map(_.toInt)
        val b = readLine.split(" ", -1).map(_.toInt)
        val all = combine(a, b)
        val treeA = build(a, all)
        val treeB = build(b, all)
        val q = readLine.toInt
        for (i <- 1 to q) {
          val tmp = readLine.split(" ", -1).map(_.toInt)
          println("%.1f".format(solve(tmp(0), tmp(1), tmp(2), tmp(3), treeA, treeB, all)))
        }
      }


    }