<p>There are several squares being dropped onto the X-axis of a 2D plane.</p>

<p>You are given a 2D integer array <code>positions</code> where <code>positions[i] = [left<sub>i</sub>, sideLength<sub>i</sub>]</code> represents the <code>i<sup>th</sup></code> square with a side length of <code>sideLength<sub>i</sub></code> that is dropped with its left edge aligned with X-coordinate <code>left<sub>i</sub></code>.</p>

<p>Each square is dropped one at a time from a height above any landed squares. It then falls downward (negative Y direction) until it either lands <strong>on the top side of another square</strong> or <strong>on the X-axis</strong>. A square brushing the left/right side of another square does not count as landing on it. Once it lands, it freezes in place and cannot be moved.</p>

<p>After each square is dropped, you must record the <strong>height of the current tallest stack of squares</strong>.</p>

<p>Return <em>an integer array </em><code>ans</code><em> where </em><code>ans[i]</code><em> represents the height described above after dropping the </em><code>i<sup>th</sup></code><em> square</em>.</p>

<p>&nbsp;</p>
<p><strong class="example">Example 1:</strong></p>
<img alt="" src="https://assets.leetcode.com/uploads/2021/04/28/fallingsq1-plane.jpg" style="width: 500px; height: 505px;" />
<pre>
<strong>Input:</strong> positions = [[1,2],[2,3],[6,1]]
<strong>Output:</strong> [2,5,5]
<strong>Explanation:</strong>
After the first drop, the tallest stack is square 1 with a height of 2.
After the second drop, the tallest stack is squares 1 and 2 with a height of 5.
After the third drop, the tallest stack is still squares 1 and 2 with a height of 5.
Thus, we return an answer of [2, 5, 5].
</pre>

<p><strong class="example">Example 2:</strong></p>

<pre>
<strong>Input:</strong> positions = [[100,100],[200,100]]
<strong>Output:</strong> [100,100]
<strong>Explanation:</strong>
After the first drop, the tallest stack is square 1 with a height of 100.
After the second drop, the tallest stack is either square 1 or square 2, both with heights of 100.
Thus, we return an answer of [100, 100].
Note that square 2 only brushes the right side of square 1, which does not count as landing on it.
</pre>

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

<ul>
	<li><code>1 &lt;= positions.length &lt;= 1000</code></li>
	<li><code>1 &lt;= left<sub>i</sub> &lt;= 10<sup>8</sup></code></li>
	<li><code>1 &lt;= sideLength<sub>i</sub> &lt;= 10<sup>6</sup></code></li>
</ul>

class Node:
    def __init__(self, l, r):
        self.l = l
        self.r = r
        self.height = 0
        self.left = None
        self.right = None

class SegmentTree:
    def __init__(self, size):
        self.root = self.construct(0, size-1)
    
    def construct(self, l, r):
        cur = Node(l, r)

        if l == r:
            return cur
        
        cur.left = self.construct(l, (l+r)//2)
        cur.right = self.construct((l+r)//2+1, r)

        return cur
    
    def update(self, l, r, h):
        self.updateHelper(self.root, l, r, h)
        
    def updateHelper(self, cur, l, r, h):
        cur.height = max(cur.height, h)
        
        if cur.left and l <= cur.left.r and cur.left.l <= r:
            self.updateHelper(cur.left, l, min(cur.left.r, r), h)
        
        if cur.right and l <= cur.right.r and cur.right.l <= r:
            self.updateHelper(cur.right, max(cur.right.l, l), r, h)
        
    def query(self, l, h):
        return self.queryHelper(self.root, l, h)

    def queryHelper(self, cur, l, r):
        if not cur.left and not cur.right:
            return cur.height
        
        answer = -float('inf')
        if cur.left and l <= cur.left.r and cur.left.l <= r:
            answer = max(answer, self.queryHelper(cur.left, l, min(cur.left.r, r)))
        
        if cur.right and l <= cur.right.r and cur.right.l <= r:
            answer = max(answer, self.queryHelper(cur.right, max(cur.right.l, l), r))

        return answer

class Solution:
    def fallingSquares(self, positions: List[List[int]]) -> List[int]:
        coords = set()

        for left, size in positions:
            coords.add(left)
            coords.add(left+size)
        
        comp = dict()
        for i, coord in enumerate(sorted(coords)):
            comp[coord] = i

        answer = []

        seg = SegmentTree(len(comp))

        def bfs():
            q = deque([seg.root, 'x'])

            while len(q) > 1:
                cur = q.popleft()

                if cur == 'x':
                    q.append('x')
                    print()
                else:
                    print(cur.l, cur.r, cur.height)

                    if cur.left:
                        q.append(cur.left)
                    if cur.right:
                        q.append(cur.right)

        print(comp)
        for left, size in positions:
            l = comp[left]
            r = comp[left+size]-1
            
            maxh = seg.query(l, r)
            print(l, r, maxh)
            newh = maxh+size
            print(newh)
            print()
            seg.update(l, r, newh)

            if not answer:
                answer.append(newh)
            else:
                answer.append(max(answer[-1], newh))

            # bfs()
            # print('\n', 'done', '\n')
        
        return answer


18100