We're simulating squares being dropped onto the X-axis. Each square has a left coordinate and a side length. When a square is dropped, it falls until it either hits the top of a previously dropped square or the ground. Two squares overlap only if they share a range of X-coordinates with nonzero length. Touching at a single edge does not count.
So when square i occupies the interval [left_i, left_i + sideLength_i), it will land on top of any previously placed square whose interval overlaps with this range. Its landing height is the maximum top of all overlapping squares, plus its own side length.
After each drop, we need to report the global maximum height across all placed squares so far. The challenge is efficiently determining which previously placed squares overlap with the new one and what the maximum height is in that overlapping region.
1 <= positions.length <= 1000. With at most 1000 squares, an O(n^2) solution runs in about 1 million operations, which is fast enough.1 <= left_i <= 10^8. Coordinates can be large, so we cannot index an array directly by position. With at most 1000 squares there are at most 2000 distinct coordinate values, which coordinate compression can map to a small range.1 <= sideLength_i <= 10^6. The rightmost coordinate reaches left + side, up to about 1.01 x 10^8, and stacked heights reach up to 1000 x 10^6 = 10^9, which still fits in a 32-bit signed integer.Maintain a list of all previously placed squares, each described by its interval [left, right) and its top height. When a new square drops, scan through every previous square, check whether its interval overlaps with the new square's interval, and track the maximum height among all overlapping squares. The new square's top is that maximum plus its own side length.
Since n is at most 1000, scanning all previous squares for each new drop is O(n) per drop, giving O(n^2) total, about a million operations.
(left, right, height) tuples.maxHeight = 0 to track the global tallest stack.[left, sideLength] in the input:right = left + sideLength.base = 0 (the height this square will land on).[left, right), update base = max(base, that square's top height).base + sideLength.(left, right, base + sideLength) to the placed squares list.maxHeight = max(maxHeight, base + sideLength).maxHeight in the answer.The scan over all previous squares is the bottleneck. The next approach replaces it with a data structure that answers "what is the maximum height in this interval?" and applies a range update, both in O(log n) time.
A segment tree supports both operations the brute force struggles with: the maximum value over any range and a range update, each in O(log n) time. The new square's landing height is the maximum over its interval, and placing the square is a range update of that interval to the new top height.
The obstacle is that coordinates reach 10^8, so a segment tree indexed directly by X-coordinate would need 10^8 leaves. With at most 1000 squares there are at most 2000 distinct coordinate values, since each square contributes a left and a right. Coordinate compression maps these values to a compact range of indices, and the segment tree is built over those indices instead.
Coordinate compression works as follows: collect all left and right endpoints, sort and deduplicate them, then map each coordinate to its position in this sorted list. The tree then has at most 2000 leaves, each representing the gap between two consecutive coordinates.
For each new square dropping onto interval [left, right):
left and right to their compressed indices.A square occupies the half-open interval [left, right), so the rightmost coordinate it covers is just below right. In compressed indices, the cell starting at index right lies entirely outside the square, so the query and update span [index(left), index(right) - 1]. This matches the edge-touching rule: a square at [2, 5) and a square at [5, 7) share no cell, because index 5 belongs only to the second square. Using index(right) instead of index(right) - 1 would let neighbors that only touch report a false overlap.
Range updates use lazy propagation to stay logarithmic. When a range update covers a whole node, the value is recorded on that node and a pending value is left in its lazy slot rather than written to every leaf. The pending value is pushed to the children only when a later query or update descends through the node.
[left, sideLength]:right = left + sideLength.left and for the last coordinate before right.queryResult + sideLength.