<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 {
private:
    inline static int left(int node){return 2*node;} const
    inline static int right(int node){return 2*node + 1;} const
    void push(int node){
        if (lazy[node] == -1) return;
        int node_l = left(node);
        int node_r = right(node);
        tree[node_l] = tree[node_r] = lazy[node];
        lazy[node_l] = lazy[node_r] = lazy[node];
        lazy[node] = -1;
    }
    int max(int node, int extent_l, int extent_r, int query_l, int query_r){
        if (extent_l > extent_r) return -1;
        if (query_l <= extent_l && extent_r <= query_r) return tree[node];
        if (extent_l == extent_r) return -1;
        push(node);
        int extent_m = (extent_l + extent_r) / 2;
        int max_l = max(left(node), extent_l, extent_m, query_l, query_r);
        int max_r = max(right(node), extent_m+1, extent_r, query_l, query_r);
        return std::max(max_l, max_r);
    }

    void update(int node, int extent_l, int extent_r, int update_l, int update_r, int update_value){
        if (extent_l > extent_r) return;
        if (extent_l == extent_r && (extent_l < update_l || extent_r > update_r)) return;
        if (update_l <= extent_l && extent_r <= update_r)
        {
            tree[node] = update_value;
            lazy[node] = update_value;
        } else {
            push(node);
            int extent_m = (extent_l + extent_r)/2;
            int node_l = left(node);
            int node_r = right(node);
            update(node_l, extent_l, extent_m, update_l, update_r, update_value);
            update(node_r, extent_m+1, extent_r, update_l, update_r, update_value);
            tree[node] = std::max(tree[node_l], tree[node_r]);
        }
    }
    const static int N = 1e5 + 2;
    array<int, 4*N> tree{};
    array<int, 4*N> lazy{};
public:
    vector<int> fallingSquares(vector<vector<int>>& positions) {
        unordered_map<int, int> index;
        set<int> coordinates;
        auto block_start = [](const vector<int>& position)->int {return position[0];};
        auto block_end = [](const vector<int>& position)->int{return position[0] + position[1] - 1;};
        for (const auto& position : positions){
            coordinates.insert(block_start(position));
            coordinates.insert(block_end(position));
        }
        const static int extent_l = 1;
        int extent_r = 1;
        for (auto coordinate: coordinates){
            index[coordinate] = extent_r;
            extent_r++;
        }
        vector<int> ans;
        for (const auto& position : positions){
            int l = index[block_start(position)];
            int r = index[block_end(position)];
            int new_height_in_span = max(extent_l, extent_l, extent_r, l, r) + position[1];
            update(extent_l, extent_l, extent_r, l, r, new_height_in_span);
            ans.push_back(ans.empty() ? new_height_in_span : std::max(ans.back(), new_height_in_span));
        }
        return ans;
    }
};
21585