<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:
    static bool position_comp(vector<int> a, vector<int> b){return (a.at(0) + a.at(1) < b.at(0) + b.at(1));}

    function<bool(const vector<int>& a, const vector<int>& b)> \
        height_comp = [](const vector<int>& a, const vector<int>& b){return a.at(2) > b.at(2);};
public:
    

void create_segment_arr(vector<int>& seg_borders, vector <vector<int>> positions_cpy, const int seg_count){
    
    seg_borders.at(0) = 0;
    for (short seg = 1; seg < seg_count; seg++){
        int relative_pos = seg*(positions_cpy.size() / (float)seg_count);
        nth_element(
            positions_cpy.begin(),
            positions_cpy.begin() + relative_pos, 
            positions_cpy.end(),
            position_comp
        );
        seg_borders.at(seg) = positions_cpy.at(relative_pos).at(0) + positions_cpy.at(relative_pos).at(1) / 2;
    }
    nth_element( positions_cpy.begin(), positions_cpy.begin() + (positions_cpy.size()-1), positions_cpy.end(), position_comp);
    seg_borders.at(seg_borders.size()-1) = positions_cpy.at(positions_cpy.size()-1).at(0) + \
        positions_cpy.at(positions_cpy.size()-1).at(1);
}

short xpoint_to_seg(int point, const vector<int>& seg_borders){
    for (int i = 0; i < seg_borders.size(); i++){
        if (point <= seg_borders.at(i+1))
            return i;
    }
    return seg_borders.size()-2;
}

int get_block_collision_height(int point, int point2, const multiset<vector<int>, decltype(height_comp)>& block_set){
    for (vector<int> block : block_set){
        if ( 
            (point >= block.at(0) && point < block.at(0) + block.at(1)) ||
            (point2 > block.at(0) && point2 <= block.at(0) + block.at(1)) ||
            (block.at(0) > point && block.at(0) < point2) ||
            (point == block.at(0) && point2 == block.at(0) + block.at(1))
        ){
            return block.at(2);
        }
    }
    return 0;
} 
short get_segment_count(int positions_size){
    if (positions_size > 10){
        return 2;
    }
    else if (positions_size > 80){
        return 4;
    }
    else if (positions_size > 400){
        return 8;
    }
    else{
        return 1;
    }
}
vector<int> fallingSquares(vector<vector<int>>& positions) {
    
    using segSet = multiset<vector<int>, decltype(height_comp)>;

    vector <int> results(positions.size());
    const short seg_count = get_segment_count(positions.size());
    vector<int> seg_borders(seg_count+1);

    vector<segSet> seg_prio_sets;

    for (int i = 0; i < seg_count; i++){
        seg_prio_sets.push_back(segSet(height_comp));
    }

    create_segment_arr(seg_borders, positions, seg_count);

    for(int i = 0; i < positions.size(); i++){
        vector <int> fal_block = {positions.at(i).at(0), positions.at(i).at(1), 0};
        short left_point_seg = xpoint_to_seg(fal_block.at(0), seg_borders);
        short right_point_seg = xpoint_to_seg(fal_block.at(0) + fal_block.at(1), seg_borders);

        int highest_collider = 0;
        if (left_point_seg != right_point_seg){
            for (short seg = left_point_seg; seg <= right_point_seg; seg++){
                int local_height = get_block_collision_height(
                    fal_block.at(0), 
                    fal_block.at(0) + fal_block.at(1), 
                    seg_prio_sets.at(seg)
                ); 
                if (local_height > highest_collider){
                    highest_collider = local_height;
                }
            }
            
        }
        else{
            highest_collider = get_block_collision_height(fal_block.at(0), fal_block.at(0) + fal_block.at(1), 
                    seg_prio_sets.at(left_point_seg)
                ); 
        }
        fal_block.at(2) = highest_collider + fal_block.at(1);
        
        for (short seg = left_point_seg; seg <= right_point_seg; seg++){
            seg_prio_sets.at(seg).insert(fal_block);
            if (i == 0){
                results.at(0) = fal_block.at(2);
            }
            else if ( seg_prio_sets.at(seg).begin()->at(2) > results.at(i-1)){
                results.at(i) = seg_prio_sets.at(seg).begin()->at(2);
            }
        }
        if (!results.at(i)){
            results.at(i) = results.at(i-1);
        }
    }

    return results;
}
};
28505