在无限长的数轴(即 x 轴)上,我们根据给定的顺序放置对应的正方形方块。
第 i
个掉落的方块(positions[i] = (left, side_length)
)是正方形,其中 left 表示该方块最左边的点位置(positions[i][0]),side_length 表示该方块的边长(positions[i][1])。
每个方块的底部边缘平行于数轴(即 x 轴),并且从一个比目前所有的落地方块更高的高度掉落而下。在上一个方块结束掉落,并保持静止后,才开始掉落新方块。
方块的底边具有非常大的粘性,并将保持固定在它们所接触的任何长度表面上(无论是数轴还是其他方块)。邻接掉落的边不会过早地粘合在一起,因为只有底边才具有粘性。
返回一个堆叠高度列表 ans
。每一个堆叠高度 ans[i]
表示在通过 positions[0], positions[1], ..., positions[i]
表示的方块掉落结束后,目前所有已经落稳的方块堆叠的最高高度。
示例 1:
输入: [[1, 2], [2, 3], [6, 1]] 输出: [2, 5, 5] 解释: 第一个方块positions[0] = [1, 2]
掉落:_aa _aa -------
方块最大高度为 2 。 第二个方块positions[1] = [2, 3]
掉落:__aaa __aaa __aaa _aa__ _aa__ --------------
方块最大高度为5。 大的方块保持在较小的方块的顶部,不论它的重心在哪里,因为方块的底部边缘有非常大的粘性。 第三个方块positions[1] = [6, 1]
掉落:__aaa __aaa __aaa _aa _aa___a --------------
方块最大高度为5。 因此,我们返回结果[2, 5, 5]。
示例 2:
输入: [[100, 100], [200, 100]] 输出: [100, 100] 解释: 相邻的方块不会过早地卡住,只有它们的底部边缘才能粘在表面上。
注意:
1 <= positions.length <= 1000
.1 <= positions[i][0] <= 10^8
.1 <= positions[i][1] <= 10^6
.
方法一:线段树
线段树将整个区间分割为多个不连续的子区间,子区间的数量不超过 log(width)
。更新某个元素的值,只需要更新 log(width)
个区间,并且这些区间都包含在一个包含该元素的大区间内。区间修改时,需要使用懒标记保证效率。
- 线段树的每个节点代表一个区间;
- 线段树具有唯一的根节点,代表的区间是整个统计范围,如
[1, N]
; - 线段树的每个叶子节点代表一个长度为 1 的元区间
[x, x]
; - 对于每个内部节点
[l, r]
,它的左儿子是[l, mid]
,右儿子是[mid + 1, r]
, 其中mid = ⌊(l + r) / 2⌋
(即向下取整)。
class Node:
def __init__(self, l, r):
self.left = None
self.right = None
self.l = l
self.r = r
self.mid = (l + r) >> 1
self.v = 0
self.add = 0
class SegmentTree:
def __init__(self):
self.root = Node(1, int(1e9))
def modify(self, l, r, v, node=None):
if l > r:
return
if node is None:
node = self.root
if node.l >= l and node.r <= r:
node.v = v
node.add = v
return
self.pushdown(node)
if l <= node.mid:
self.modify(l, r, v, node.left)
if r > node.mid:
self.modify(l, r, v, node.right)
self.pushup(node)
def query(self, l, r, node=None):
if l > r:
return 0
if node is None:
node = self.root
if node.l >= l and node.r <= r:
return node.v
self.pushdown(node)
v = 0
if l <= node.mid:
v = max(v, self.query(l, r, node.left))
if r > node.mid:
v = max(v, self.query(l, r, node.right))
return v
def pushup(self, node):
node.v = max(node.left.v, node.right.v)
def pushdown(self, node):
if node.left is None:
node.left = Node(node.l, node.mid)
if node.right is None:
node.right = Node(node.mid + 1, node.r)
if node.add:
node.left.v = node.add
node.right.v = node.add
node.left.add = node.add
node.right.add = node.add
node.add = 0
class Solution:
def fallingSquares(self, positions: List[List[int]]) -> List[int]:
ans = []
mx = 0
tree = SegmentTree()
for l, w in positions:
r = l + w - 1
h = tree.query(l, r) + w
mx = max(mx, h)
ans.append(mx)
tree.modify(l, r, h)
return ans
class Node {
Node left;
Node right;
int l;
int r;
int mid;
int v;
int add;
public Node(int l, int r) {
this.l = l;
this.r = r;
this.mid = (l + r) >> 1;
}
}
class SegmentTree {
private Node root = new Node(1, (int) 1e9);
public SegmentTree() {
}
public void modify(int l, int r, int v) {
modify(l, r, v, root);
}
public void modify(int l, int r, int v, Node node) {
if (l > r) {
return;
}
if (node.l >= l && node.r <= r) {
node.v = v;
node.add = v;
return;
}
pushdown(node);
if (l <= node.mid) {
modify(l, r, v, node.left);
}
if (r > node.mid) {
modify(l, r, v, node.right);
}
pushup(node);
}
public int query(int l, int r) {
return query(l, r, root);
}
public int query(int l, int r, Node node) {
if (l > r) {
return 0;
}
if (node.l >= l && node.r <= r) {
return node.v;
}
pushdown(node);
int v = 0;
if (l <= node.mid) {
v = Math.max(v, query(l, r, node.left));
}
if (r > node.mid) {
v = Math.max(v, query(l, r, node.right));
}
return v;
}
public void pushup(Node node) {
node.v = Math.max(node.left.v, node.right.v);
}
public void pushdown(Node node) {
if (node.left == null) {
node.left = new Node(node.l, node.mid);
}
if (node.right == null) {
node.right = new Node(node.mid + 1, node.r);
}
if (node.add != 0) {
Node left = node.left, right = node.right;
left.add = node.add;
right.add = node.add;
left.v = node.add;
right.v = node.add;
node.add = 0;
}
}
}
class Solution {
public List<Integer> fallingSquares(int[][] positions) {
List<Integer> ans = new ArrayList<>();
SegmentTree tree = new SegmentTree();
int mx = 0;
for (int[] p : positions) {
int l = p[0], w = p[1], r = l + w - 1;
int h = tree.query(l, r) + w;
mx = Math.max(mx, h);
ans.add(mx);
tree.modify(l, r, h);
}
return ans;
}
}
class Node {
public:
Node* left;
Node* right;
int l;
int r;
int mid;
int v;
int add;
Node(int l, int r) {
this->l = l;
this->r = r;
this->mid = (l + r) >> 1;
this->left = this->right = nullptr;
v = add = 0;
}
};
class SegmentTree {
private:
Node* root;
public:
SegmentTree() {
root = new Node(1, 1e9);
}
void modify(int l, int r, int v) {
modify(l, r, v, root);
}
void modify(int l, int r,int v, Node* node) {
if (l > r) return;
if (node->l >= l && node->r <= r)
{
node->v = v;
node->add = v;
return;
}
pushdown(node);
if (l <= node->mid) modify(l, r, v, node->left);
if (r > node->mid) modify(l, r, v, node->right);
pushup(node);
}
int query(int l, int r) {
return query(l, r, root);
}
int query(int l, int r, Node* node) {
if (l > r) return 0;
if (node->l >= l && node-> r <= r) return node->v;
pushdown(node);
int v = 0;
if (l <= node->mid) v = max(v, query(l, r, node->left));
if (r > node->mid) v = max(v, query(l, r, node->right));
return v;
}
void pushup(Node* node) {
node->v = max(node->left->v, node->right->v);
}
void pushdown(Node* node) {
if (!node->left) node->left = new Node(node->l, node->mid);
if (!node->right) node->right = new Node(node->mid + 1, node->r);
if (node->add)
{
Node* left = node->left;
Node* right = node->right;
left->v = node->add;
right->v = node->add;
left->add = node->add;
right->add = node->add;
node->add = 0;
}
}
};
class Solution {
public:
vector<int> fallingSquares(vector<vector<int>>& positions) {
vector<int> ans;
SegmentTree* tree = new SegmentTree();
int mx = 0;
for (auto& p : positions)
{
int l = p[0], w = p[1], r = l + w - 1;
int h = tree->query(l, r) + w;
mx = max(mx, h);
ans.push_back(mx);
tree->modify(l, r, h);
}
return ans;
}
};