<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 {
public:
    class tree{
    public:
        vector <int> seg, lazy;
        tree(int n){
            seg.resize(4*n + 1);
            lazy.resize(4*n + 1);
        }

        void build(int index, int l, int r, vector <int> &nums){
            if (l == r){
                seg[index] = 0;
                lazy[index] = 0;
                return;
            }

            int mid = (l + r) / 2;
            build(2*index + 1, l, mid, nums);
            build(2*index + 2, mid+1, r, nums);

            seg[index] = max(seg[2*index + 1], seg[2*index + 2]);
            lazy[index] = 0;
        }

        int query(int index, int l, int r, int lo, int hi){
            if (lazy[index] != 0){
                seg[index] = max(seg[index], lazy[index]);
                if (l != r) lazy[2*index + 1] = lazy[2*index + 2] = lazy[index];
                lazy[index] = 0;
            }

            if (l > hi || r < lo) return 0;
            
            if (lo <= l && r <= hi) return seg[index];

            int mid = (l + r) / 2;
            seg[index] = max(query(2*index + 1, l, mid, lo, hi), query(2*index + 2, mid+1, r, lo, hi));
            return seg[index];
        }

        void update(int index, int l, int r, int lo, int hi, int val){
            if (lazy[index] != 0){
                seg[index] = max(seg[index], lazy[index]);
                if (l != r) lazy[2*index + 1] = lazy[2*index + 2] = lazy[index];
                lazy[index] = 0;
            }

            if (l > hi || r < lo) return;
            
            if (lo <= l && r <= hi){
                seg[index] = val;
                if (l != r) lazy[2*index + 1] = lazy[2*index + 2] = val;
                return;
            }

            int mid = (l + r) / 2;
            update(2*index + 1, l, mid, lo, hi, val);
            update(2*index + 2, mid+1, r, lo, hi, val);
            seg[index] = max(seg[2*index + 1], seg[2*index + 2]);
        }
    };

    vector<int> fallingSquares(vector<vector<int>>& positions) {
        int n = positions.size();
        vector <int> start;
        for (auto i : positions) start.push_back(i[0]);
        sort(start.begin(), start.end());
        // for (auto i : start) cout << i << " ";
        // cout << endl;
        tree t(n);
        t.build(0, 0, n-1, start);
        vector <int> ans;
        for (auto i : positions){
            int curr_x = i[0];
            int height = i[1];
            int x = lower_bound(start.begin(), start.end(), curr_x) - start.begin(), y;
            auto it = lower_bound(start.begin(), start.end(), height - 1 + curr_x);
            if (it == start.end()) y = it - start.begin() - 1;
            else if (*it == curr_x + height - 1) y = it - start.begin();
            else y = it - start.begin() - 1;
            // cout << x << " " << y << endl;
            int curr = t.query(0, 0, n-1, x, y);
            t.update(0, 0, n-1, x, y, curr + height);
            ans.push_back(t.query(0, 0, n-1, 0, n-1));
        }
        return ans;
    }
};
16395