<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 Solution:
    def fallingSquares(self, positions: List[List[int]]) -> List[int]:
        squares = []

        def findHeight(l_, r_):
            maxx = 0
            for l, r, h in squares:
                over_l, over_r = max(l_, l), min(r_, r)
                if over_l < over_r and l <= over_l and over_r <= r:
                    maxx = max(maxx, h)

            return maxx

        ans = []

        for l, w in positions:
            submax = findHeight(l, l+w)
            h = submax+w
            squares.append((l, l+w, h))
            m = ans[-1] if len(ans) > 0 else 0
            ans.append(max(m, h))

        return ans       


    def fallingSquares(self, positions: List[List[int]]) -> List[int]:
        points = set()
        for l, w in positions:
            points.add(l)
            points.add(l+w)
        index = {x: i for i, x in enumerate(sorted(points))}
        heights = [0] * len(index)

        def query(l, r):
            maxx = 0
            for i in range(l, r):
                maxx = max(maxx, heights[i])

            return maxx
        
        def update(l, r, val):
            for i in range(l, r):
                heights[i] = max(heights[i], val)

        ans = []
        maxx = 0
        for l, w in positions:
            L = index[l]
            R = index[l+w]
            h = query(L, R) + w
            update(L, R, h)

            maxx = max(maxx, h)
            ans.append(maxx)

        return ans

    def fallingSquares(self, positions: List[List[int]]) -> List[int]:
        points = set()
        for l, w in positions:
            points.add(l)
            points.add(l+w-1)
        index = {x: i for i, x in enumerate(sorted(points))}
        
        self.tree = SegmentTree(len(index))
        ans = []
        maxx = 0
        for l, w in positions:
            L = index[l]
            R = index[l+w-1]
            h = self.tree.query(L, R) + w
            self.tree.update(L, R, h)

            maxx = max(maxx, h)
            ans.append(maxx)


        return ans

class SegmentTree:
    def __init__(self, size):
        self.n = size
        self.total = 1 << ceil(log(size)/log(2))+1
        self.tree = [0]*(self.total)
        self.lazy = [0]*(self.total)

    def _prop(self, idx, nl, nr):
        u = self.lazy[idx]
        self.tree[idx] = max(self.tree[idx], u)
        self.lazy[idx] = 0

        if nl != nr:
            self.lazy[2*idx] = max(self.lazy[2*idx], u)
            self.lazy[2*idx+1] = max(self.lazy[2*idx+1], u)

    def query(self, l, r):
        return self._query(1, l, r, 0, self.n-1)
    
    def _query(self, idx, ql, qr, nl, nr):
        if nl > nr or qr < nl or ql > nr:
            return 0
        
        if self.lazy[idx] != 0:
            self._prop(idx, nl, nr)

        if nl >= ql and qr >= nr:
            return self.tree[idx]
        
        mid = nl + (nr - nl) // 2
        return max(self._query(idx*2, ql, qr, nl, mid), 
            self._query(idx*2 + 1, ql, qr, mid+1, nr)
        )

    def update(self, l, r, val):
        return self._update(1, l, r, 0, self.n-1, val)

    def _update(self, idx, ql, qr, nl, nr, v):
        if nl > nr or qr < nl or ql > nr:
            return

        if self.lazy[idx] != 0:
            self._prop(idx, nl, nr)

        if nl >= ql and nr <= qr:
            self.tree[idx] = max(self.tree[idx], v)
            if nl != nr:
                self.lazy[2*idx] = max(self.lazy[2*idx], v)
                self.lazy[2*idx+1] = max(self.lazy[2*idx+1], v)
            return 

        mid = nl + (nr - nl) // 2
        self._update(idx*2, ql, qr, nl, mid, v)
        self._update(idx*2+1, ql, qr, mid+1, nr, v)

        self.tree[idx] = max(self.tree[2*idx], self.tree[2*idx+1])
17900