Stock Prediction
Difficulty: Hard

George is very concerned about the stock options his company has granted him, because the company's stock price has fluctuated unpredictably and has often failed to meet expectations.  With this in mind, George has decided to sell his options.  Before doing so, he would like to perform a series of calculations.

Stock price history is presented as an array of positive integers, $A = \{a_0, a_1, \ldots, a_{n-1}\}$, which represents the average price per day of that stock. For a given day $d\ (0 \le d < n)$ and margin $M$, George needs to find the longest subarray containing the day's entry as a minimum,  $a_d$, and all other entries not exceeding $a_d+M$.

That is, he has to find the longest subarray, $A[l, r] = \{a_l, a_{l+1}, \ldots, a_r\}$, such that 

- $0 \le l \le d \le r < n$
- $a_d = minimum\{A[l, r]\}$
- $ \forall i \in [l, r], a_d \le a_i \le a_d + M$

George asks you to help him solve this problem.

Input Format:
The first list contains an integer $n$ which represents the length of the array $A$. The second line contains $n$ space-separated integers, $a_0, a_1, \ldots, a_{n-1}$, which represent the element of array $A$. The next line contains the number of queries $Q$. Each of the subsequent $Q$ lines contain two integers $d$ and $M$ which represent the index of the element, which should be minimal and be included in subarray, and margin, respectively.  

Output Format:
For each query output the length of the longest subarray with the required properties.

**Constraints**  
$1 \le n \le 5\cdot 10^4$  
$1 \le A[i] \le 10^9, 0 \le i < n$  
$1 \le Q \le 10^5$  
$0 \le d < n$  
$0 \le M \le 10^9$

Sample Input:
    5
    3 5 2 6 1
    2
    0 2
    2 3

Sample Output:
    2
    3

Python 3 starter code:


Reference solution (Python):
    import java.io.{BufferedReader, FileReader, InputStreamReader, Reader}
    object Solution {
      class Query(_index: Int, _margin: Int) {
        def index = _index
        def margin = _margin
      }
      def parseQuery(s: String): Query = {
        val elements = s.split(' ').map(Integer.parseInt).toList
        new Query(elements.head, elements.tail.head)
      }
      def readData(reader: BufferedReader): (Array[Int], Array[Query]) = {
        reader.readLine() // ignore number of elements
        val elements = reader.readLine().split(' ').map(Integer.parseInt).toList.toArray
        val numQueries = Integer.parseInt(reader.readLine())
        val queries = new Array[Query](numQueries)
        for (i <- 0 to numQueries - 1) {
          queries(i) = parseQuery(reader.readLine())
        }
        Tuple2(elements, queries)
      }
      class Range(val begin: Int, val end: Int) {
        def split(): (Range, Range) = {
          val m = (begin + end) >> 1
          Tuple2(new Range(begin, m), new Range(m, end))
        }
        def isEmpty = begin >= end
        def isSingle = begin + 1 == end
        def contains(i: Int) = begin <= i && i < end
        def equals(o: Range) = begin == o.begin && end == o.end
        def doesIntersect(o: Range) = {
          begin < o.end && o.begin < end
        }
        def restrictBy(r: Range): Range = {
          new Range(Math.max(begin, r.begin), Math.min(end, r.end))
        }
        def concatRight(o: Range): Range = {
          if (end != o.begin) {
            throw new RuntimeException("Cannot concat non-adjacent ranges")
          }
          new Range(begin, o.end)
        }
        def length: Int = end - begin
        override def toString = "(%d, %d)".format(begin, end)
      }
      class Node[T](val left: Node[T], val right: Node[T], val range: Range, val e: T) {
        def this(range: Range, e: T) = this(null, null, range, e)
      }
      class SegmentsTree[T](root: Node[T], op: (T, T) => T, default: T) {
        def size: Int = root.range.length

        def update(index: Int, value: T): SegmentsTree[T] = {
          if (root.range.contains(index)) {
            new SegmentsTree[T](updateImpl(root, index, value), op, default)
          } else {
            this
          }
        }

        def rmq(begin: Int, end: Int): T = {
          rmqImpl(root, new Range(begin, end).restrictBy(root.range))
        }

        private def updateImpl(node: Node[T], i: Int, v: T): Node[T] = {
          if (node.range.isSingle) {
            new Node[T](node.range, v)
          } else {
            val split = node.range.split()
            val left = if (split._1.contains(i)) {
              updateImpl(node.left, i, v)
            } else {
              node.left
            }
            val right = if (split._2.contains(i)) {
              updateImpl(node.right, i, v)
            } else {
              node.right
            }
            new Node[T](left, right, left.range.concatRight(right.range), op(left.e, right.e))
          }
        }

        private def rmqImpl(node: Node[T], query: Range): T = {
          //System.err.println(node)
          //System.err.println(node.range)
          //System.err.println(node.range, query)
          if (query.isEmpty) {
            default
          } else if (query.equals(node.range)) {
            node.e
          } else {
            val split = node.range.split()
            var result = default
            if (split._1.doesIntersect(query)) {
              result = op(
                result,
                rmqImpl(node.left, query.restrictBy(split._1)))
            }
            if (split._2.doesIntersect(query)) {
              result = op(
                result,
                rmqImpl(node.right, query.restrictBy(split._2))
              )
            }
            result
          }
        }
      }
      object IntSegmentsTree {
        def apply(range: Range, op: (Int, Int) => Int, default: Int) = {
          def buildImpl(range: Range): Node[Int] = {
            if (range.isSingle) {
              new Node[Int](range, default)
            } else {
              val split = range.split()
              val left = buildImpl(split._1)
              val right = buildImpl(split._2)
              new Node[Int](left, right, left.range.concatRight(right.range), op(left.e, right.e))
            }
          }
          new SegmentsTree[Int](buildImpl(range), op, default)
        }
      }
      def compress(sequence: Array[Int]): Array[Int] = {
        sequence.sortWith(_ < _).distinct
      }
      class Compressor(data: Array[Int]) {
        def indexOfMaxNotGreaterThan(element: Int): Int = {
          indexOfMaxNotGreaterThanImpl(new Range(0, data.length), element)
        }
        def size: Int = data.length
        private def indexOfMaxNotGreaterThanImpl(range: Range, element: Int): Int = {
          if (range.isSingle) {
            range.begin
          } else {
            val split = range.split()
            if (data(split._2.begin) <= element) {
              indexOfMaxNotGreaterThanImpl(split._2, element)
            } else {
              indexOfMaxNotGreaterThanImpl(split._1, element)
            }
          }
        }
      }
      def generateTrees(compressor: Compressor, elements: Array[Int]): (Array[SegmentsTree[Int]], Array[SegmentsTree[Int]]) = {
        val INF = 1000000000
        val leftTrees = new Array[SegmentsTree[Int]](elements.length)
        val rightTrees = new Array[SegmentsTree[Int]](elements.length)
        var treeRight = IntSegmentsTree(new Range(0, compressor.size), Math.min, INF)
        var treeLeft = IntSegmentsTree(new Range(0, compressor.size), Math.max, -INF)
        for (i <- elements.length - 1 to 0 by -1) {
          rightTrees(i) = treeRight
          treeRight = treeRight.update(compressor.indexOfMaxNotGreaterThan(elements(i)), i)
        }
        for (i <- 0 to elements.length - 1) {
          leftTrees(i) = treeLeft
          treeLeft = treeLeft.update(compressor.indexOfMaxNotGreaterThan(elements(i)), i)
        }
        (leftTrees, rightTrees)
      }

      def maxIntervalLength(
            elements: Array[Int],
            precalc: (Array[SegmentsTree[Int]], Array[SegmentsTree[Int]]),
            compressor: Compressor,
            query: Query): Int = {
        val leftTree = precalc._1(query.index)
        val rightTree = precalc._2(query.index)
        val minPriceIndex = compressor.indexOfMaxNotGreaterThan(elements(query.index))
        val maxPriceIndex = compressor.indexOfMaxNotGreaterThan(elements(query.index) + query.margin)
        val range = new Range(
          Math.max(
            leftTree.rmq(0, minPriceIndex),
            leftTree.rmq(maxPriceIndex + 1, leftTree.size)
          ),
          Math.min(
            rightTree.rmq(0, minPriceIndex),
            rightTree.rmq(maxPriceIndex + 1, rightTree.size)
          ))
        range.restrictBy(new Range(-1, elements.length)).length - 1
      }
      def solve(iStreamReader: Reader): Unit = {
        val reader = new BufferedReader(iStreamReader)
        val data = readData(reader)
        val elements = data._1
        val queries = data._2

        val compressor = new Compressor(compress(elements))
        val precalc = generateTrees(compressor, elements)

        queries.map(query => maxIntervalLength(elements, precalc, compressor, query)).map(println)
      }
      def main(arguments: Array[String]) =
        solve(if (arguments.length == 0) new InputStreamReader(System.in) else new FileReader(arguments(0)))
    }