***
 
from statistics import median
from typing import List, Tuple
def isInRange(q1:float, v:float, q2:float):
    if q1 is not None and q2 is not None and q1<=v<=q2: return True
    elif q1 is None and q2 is not None and v<=v: return True
    elif q1 is not None and q2 is None and q1<=v: return True
    return False
def isInWindow(p:Tuple, qx1:float, qx2:float, qy1:float, qy2:float):
    return isInRange(qx1, p[0], qx2) and isInRange(qy1, p[1], qy2)
class IntervalNode:
    def __init__(self, xmed:float):
        self.xmed=xmed
        self.leftChild, self.rightChild=None, None
        self.intervals=[]
        self.taul, self.taur=[],[]
class IntervalTree:
    def __init__(self, I:List):
        self.rootNode=self._create(I)
    def _create(self, I:list):
        if len(I) == 0: return None
        else:
            epoints=set(map(lambda si:si[0][0], I)).union(set((map(lambda si: si[0][1], I))))
            xmed=median(epoints)
            n=IntervalNode(xmed)
            Ileft=list(filter(lambda si:si[0][0]<xmed and si[0][1]<xmed, I))
            Iright=list(filter(lambda si:si[0][0]>xmed and si[0][1]>xmed, I))
            Imed=list(filter(lambda si:si not in Ileft+Iright, I))
            n.intervals=Imed
            nl,nr=self._create(Ileft), self._create(Iright)
            n.leftChild, n.rightChild=nl,nr
            if len(Imed) > 0:
                n.taul+=list(map(lambda si:{'point':(min(si[0][0], si[0][1]), si[1]), 'interval':si}, Imed))
                n.taur+=list(map(lambda si:{'point':(max(si[0][0], si[0][1]), si[1]), 'interval':si}, Imed))
            return n