<p>You are given a 2D integer array <code>rectangles</code> where <code>rectangles[i] = [l<sub>i</sub>, h<sub>i</sub>]</code> indicates that <code>i<sup>th</sup></code> rectangle has a length of <code>l<sub>i</sub></code> and a height of <code>h<sub>i</sub></code>. You are also given a 2D integer array <code>points</code> where <code>points[j] = [x<sub>j</sub>, y<sub>j</sub>]</code> is a point with coordinates <code>(x<sub>j</sub>, y<sub>j</sub>)</code>.</p>

<p>The <code>i<sup>th</sup></code> rectangle has its <strong>bottom-left corner</strong> point at the coordinates <code>(0, 0)</code> and its <strong>top-right corner</strong> point at <code>(l<sub>i</sub>, h<sub>i</sub>)</code>.</p>

<p>Return<em> an integer array </em><code>count</code><em> of length </em><code>points.length</code><em> where </em><code>count[j]</code><em> is the number of rectangles that <strong>contain</strong> the </em><code>j<sup>th</sup></code><em> point.</em></p>

<p>The <code>i<sup>th</sup></code> rectangle <strong>contains</strong> the <code>j<sup>th</sup></code> point if <code>0 &lt;= x<sub>j</sub> &lt;= l<sub>i</sub></code> and <code>0 &lt;= y<sub>j</sub> &lt;= h<sub>i</sub></code>. Note that points that lie on the <strong>edges</strong> of a rectangle are also considered to be contained by that rectangle.</p>

<p>&nbsp;</p>
<p><strong class="example">Example 1:</strong></p>
<img alt="" src="https://assets.leetcode.com/uploads/2022/03/02/example1.png" style="width: 300px; height: 509px;" />
<pre>
<strong>Input:</strong> rectangles = [[1,2],[2,3],[2,5]], points = [[2,1],[1,4]]
<strong>Output:</strong> [2,1]
<strong>Explanation:</strong> 
The first rectangle contains no points.
The second rectangle contains only the point (2, 1).
The third rectangle contains the points (2, 1) and (1, 4).
The number of rectangles that contain the point (2, 1) is 2.
The number of rectangles that contain the point (1, 4) is 1.
Therefore, we return [2, 1].
</pre>

<p><strong class="example">Example 2:</strong></p>
<img alt="" src="https://assets.leetcode.com/uploads/2022/03/02/example2.png" style="width: 300px; height: 312px;" />
<pre>
<strong>Input:</strong> rectangles = [[1,1],[2,2],[3,3]], points = [[1,3],[1,1]]
<strong>Output:</strong> [1,3]
<strong>Explanation:
</strong>The first rectangle contains only the point (1, 1).
The second rectangle contains only the point (1, 1).
The third rectangle contains the points (1, 3) and (1, 1).
The number of rectangles that contain the point (1, 3) is 1.
The number of rectangles that contain the point (1, 1) is 3.
Therefore, we return [1, 3].
</pre>

<p>&nbsp;</p>
<p><strong>Constraints:</strong></p>

<ul>
	<li><code>1 &lt;= rectangles.length, points.length &lt;= 5 * 10<sup>4</sup></code></li>
	<li><code>rectangles[i].length == points[j].length == 2</code></li>
	<li><code>1 &lt;= l<sub>i</sub>, x<sub>j</sub> &lt;= 10<sup>9</sup></code></li>
	<li><code>1 &lt;= h<sub>i</sub>, y<sub>j</sub> &lt;= 100</code></li>
	<li>All the <code>rectangles</code> are <strong>unique</strong>.</li>
	<li>All the <code>points</code> are <strong>unique</strong>.</li>
</ul>

class Fenwick2D:
    def __init__(self, xsize, ysize):
        self.bit = [[0 for _ in range(ysize+1)] for _ in range(xsize+1)]
        
    
    def update(self, x,y, val):
        while x < len(self.bit):
            _y = y
            while _y < len(self.bit[0]):
                self.bit[x][_y] += val
                _y += _y & (-_y)
            x += x & (-x)
    
    def getcum(self, x, y):
        ans = 0
        while x > 0:
            _y = y
            while _y > 0:
                ans += self.bit[x][_y]
                _y -= _y & (-_y)
            x -= x & (-x)
        return ans
    
    def debug(self):
        print("  || 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |")
        print("--------------------------------------")
        for i in range(len(self.bit)):
            ans = f"{i} || "
            for j in range(len(self.bit[0])):
                ans += f"{self.getcum(i, j)} | "
            print(ans)



class Solution:
    def countRectangles(self, rectangles: List[List[int]], points: List[List[int]]) -> List[int]:
        def compress(rectangles, points, i):
            mp = {}
            distinct_sorted_nums = sorted(
                list(
                    set(
                        [a[i] for a in rectangles] + [a[i] for a in points]
                    )
                )
            )

            for i in range(len(distinct_sorted_nums)):
                mp[distinct_sorted_nums[i]] = i + 1 # when asked with number, we want to get the compressed index
            return mp
        
        # in compress function we basically reduce the size needed for fenwick trr
        # if x = [1,5,8,90] we will make x = [1,2,3,4] as we do not need to really care about what the exact values are, we just need their relative position
        xmap = compress(rectangles, points, 0)
        ymap = compress(rectangles, points, 1)
        # print(xmap)
        # print(ymap)
        xlen = len(xmap)
        ylen = len(ymap)
        ftr = Fenwick2D(len(xmap), len(ymap))
        for x, y in rectangles:
            xx = xmap[x]
            yy = ymap[y]
            # print(f"adding {xx, yy}")
            ftr.update(xx,yy,1)

        # ftr.debug()

        ans = []
        for x, y in points:
            xx = xmap[x]
            yy = ymap[y]

            # print(f"looking at {xx, yy}")

            # total area
            total = ftr.getcum(xlen, ylen)
            # area above this rect
            above = ftr.getcum(xx-1, ylen)


            # area left of this rect
            left = ftr.getcum(xlen, yy-1)

            # common area -> digonally opp
            common = ftr.getcum(xx-1, yy-1)
            # print(f"total = {total}, common = {common}, left = {left}, above = {above}")
            ans.append(total - above - left + common)
        return ans
65099