<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 SegmentTree:
    
    def __init__(self, nums):
        self.n = len(nums)
        self.nums = [0] + nums
        N = self.n * 4
        self.vals = [0] * N
        self.update = [False] * N
        self.change = [999] * N


    def build(self, l, r, i=1):
        if l == r:
            self.vals[i] = self.nums[l]
            return
        
        m = (l+r)//2
        self.build(l, m, i*2)
        self.build(m+1, r, i*2+1)
        self.up(i)

    def down(self, i):
        if self.update[i]:
            self.lazy(i*2, self.change[i])
            self.lazy(i*2+1, self.change[i])
            self.update[i] = False
    
    def lazy(self, i, val):
        self.vals[i] = val
        self.change[i] = val
        self.update[i] = True
    
    def up(self, i):
        self.vals[i] = max(self.vals[i*2], self.vals[i*2+1])
    

    def rangeUpdate(self, jobl, jobr, jobv, l, r , i=1):
        if jobl <= l and jobr >= r:
            self.lazy(i, jobv)
            return
        m = (l+r)//2
        self.down(i)
        if jobl <= m:
            self.rangeUpdate(jobl, jobr, jobv, l, m, i*2)
        if jobr > m:
            self.rangeUpdate(jobl, jobr, jobv, m+1, r, i*2+1)
        self.up(i)

    def rangeQuery(self, jobl, jobr, l, r, i=1):
        if jobl <= l and jobr >= r:
            return self.vals[i]
        
        m = (l+r)//2
        self.down(i)
        ans = float('-inf')
        if jobl<=m:
            ans = max(ans, self.rangeQuery(jobl, jobr, l, m, i*2))
        if jobr > m:
            ans = max(ans, self.rangeQuery(jobl, jobr, m+1, r, i*2+1))
        self.up(i)
        return ans

class Solution:
    def fallingSquares(self, positions: List[List[int]]) -> List[int]:
        nums = set()
       
        for pos, length in positions:
            nums.add(pos)
            nums.add(pos+length-1)
        
        nums = list(nums)
        nums.sort()
        st = SegmentTree(nums)
        rank = {v:i+1 for i, v in enumerate(nums)}
        ans = []
        res = 0

        for i in range(len(positions)):
            left, right = rank[positions[i][0]], rank[positions[i][0] + positions[i][1] - 1]
            oldLength = st.rangeQuery(left, right, 1, st.n, 1)
            newLength = oldLength + positions[i][1]
            st.rangeUpdate(left, right, newLength, 1, st.n, 1)
            res = max(res, newLength)
            ans.append(res)
        return ans
    
    
17400