题目来源
题目描述
class Solution {
public:
vector<int> fallingSquares(vector<vector<int>>& positions) {
}
};
题目解析
这题主要需要解决两个问题:
- 当每次落下来一个方块的时候,我们需要判断它会落在哪个格子的上面。
- 由于格子能堆叠,因此需要能知道当前格子的真实高度。
格子按照顺序落下来,大致有三种可能
假设 p o s i t i o n s [ i ] = [ l e f t i , s i d e L e n g t h i ] positions[i] = [left_i, sideLength_i] positions[i]=[lefti,sideLengthi]落下来,因为它是一个正方形,其边长为 s i d e L e n g t h i sideLength_i sideLengthi,所以它的右边界为 r i g h t i = l e f t i + s i d e L e n g t h i right_i = left_i + sideLength_i righti=lefti+sideLengthi。也就是说它会落在区间 [ l e f t i , r i g h t i ] [left_i,right_i ] [lefti,righti]。问题是这个区间的高度会是多少呢?
有上面知道,落下来有三种可能:
- 之前底下完全不没有任何方块,所以要将 [ l e f t i , r i g h t i ] [left_i,right_i ] [lefti,righti]区间的高度修改为 s i d e L e n g t h i sideLength_i sideLengthi
- 贴着一个方块落下来,所以要将 [ l e f t i , r i g h t i ] [left_i,right_i ] [lefti,righti]区间的高度修改为 s i d e L e n g t h i sideLength_i sideLengthi
- 底下有一个方块,所以要将 [ l e f t i , r i g h t i ] [left_i,right_i ] [lefti,righti]区间的高度修改为 b e f o r e H e i g h t + s i d e L e n g t h i beforeHeight + sideLength_i beforeHeight+sideLengthi
最终返回所有区间上的最大高度。
我们并不需要关心方块内部是怎么放的,只需要看某个区间上的高度就可以了。
所以,这道题可以转换为如下三个问题:
- 修改指定区间上的高度为某个值
- 查询所有区间上的最大高度
问题是放方块贴边落下来时怎么修改高度呢?
- 很简单,每次修改高度时只修改 [ l e f t i , r i g h t i ) [left_i,right_i ) [lefti,righti)即可,也就是 [ l e f t i , r i g h t i − 1 ] [left_i,right_i - 1] [lefti,righti−1]
class Solution {
class SegmentTree{
std::vector<int> m_height;
std::vector<int> m_change;
std::vector<bool> m_update;
void pushUp(int idx){
m_height[idx] = std::max(m_height[idx << 1], m_height[idx << 1 | 1]);
}
// l_node表示左子树元素结点个数,r_node表示右子树结点个数
void pushDown(int idx, int l_node, int r_node){
if(m_update[idx]){
m_height[idx << 1] = m_change[idx];
m_height[idx << 1 | 1] = m_change[idx];
m_change[idx << 1] = m_change[idx];
m_change[idx << 1 | 1] = m_change[idx];
m_update[idx << 1] = true;
m_update[idx << 1 | 1] = true;
m_update[idx] = false;
}
}
public:
SegmentTree(int size){
int N = size << 2;
m_height.resize(N);
m_change.resize(N);
m_update.resize(N);
}
void update(int L, int R, int C, int l, int r, int idx){
if(L <= l && r <= R){
m_height[idx] = C;
m_change[idx] = C;
m_update[idx] = true;
return;
}
int mid = (l + r) >> 1;
int l_node = mid - l + 1, r_node = r - mid;
pushDown(idx, l_node, r_node);
if(L <= mid){
update(L, R, C, l, mid, idx << 1);
}
if(mid + 1 <= R){
update(L, R, C, mid + 1, r, idx << 1 | 1);
}
pushUp(idx);
}
int query(int L, int R, int l, int r, int idx){
if(L <= l && r <= R){
return m_height[idx];
}
int mid = (l + r) >> 1;
int l_node = mid - l + 1, r_node = r - mid;
pushDown(idx, l_node, r_node);
int left = 0, right = 0;
if(L <= mid){
left = query(L, R, l, mid, idx << 1);
}
if(mid + 1 <= R){
right = query(L, R, mid + 1, r, idx << 1 | 1);
}
return std::max(left, right);
}
};
std::map<int, int> index(vector<vector<int>>& positions){
std::set<int> pos;
for(auto arr : positions){
pos.insert(arr[0]);
pos.insert(arr[0] + arr[1] - 1);
}
std::map<int, int> map;
int cnt = 0;
for(auto idx : pos){
map.insert({idx, ++cnt});
}
return map;
}
public:
vector<int> fallingSquares(vector<vector<int>>& positions) {
std::map<int, int> map = index(positions);
int N = map.size();
SegmentTree seg(N);
int max = 0;
std:vector<int> res;
// 每落一个正方形,收集一下,所有东西组成的图像,最高高度是什么
for(auto arr : positions){
int L = map[arr[0]], R = map[arr[1] + arr[0] - 1];
int height = seg.query(L, R, 1, N, 1) + arr[1]; //计算出本区间的高度: 先查询本区间的高度 + 本格子的高度 = 本区间的高度
// 更新本次格子落下来的高度
max = std::max(max, height);
res.push_back(max);
// 将高度写入到树中
seg.update(L, R, height, 1, N, 1);
}
return res;
}
};