LC 3161(2500) 普通线段树
题目:
有一条无限长的数轴,原点在 0 处,沿着 x 轴 正 方向无限延伸。
给你一个二维数组 queries ,它包含两种操作:
操作类型 1 :queries[i] = [1, x] 。在距离原点 x 处建一个障碍物。数据保证当操作执行的时候,位置 x 处 没有 任何障碍物。
操作类型 2 :queries[i] = [2, x, sz] 。判断在数轴范围 [0, x] 内是否可以放置一个长度为 sz 的物块,这个物块需要 完全 放置在范围 [0, x] 内。如果物块与任何障碍物有重合,那么这个物块 不能 被放置,但物块可以与障碍物刚好接触
请你返回一个 bool 数组results ,如果第 i 个操作类型 2 的操作你可以放置物块,那么 results[i] 为 true ,否则为 false 。
思路:
显然使用线段树,甚至不需要区间更新,维护信息为区间最大值。
显然,把区间最大值的信息放在区间最右端最合适。如果这样的话,每个query都分成两个询问 : 0~L内最靠右的障碍物的x坐标 + x~L
因此,我们使用线段树维护区间最大值的同时,用一个集合保存障碍物信息,然后每次都查找。(注意哨兵元素)
代码:
class Solution {
vector<int> t;
void update(int x, int l, int r, int ui, int val) {
if (l == r) {
t[x] = val;
return;
}
int mid = (l + r) >> 1;
if (ui <= mid) update(x * 2, l, mid, ui, val);
else {
update(x * 2 + 1, mid + 1, r, ui, val);
}
t[x] = max(t[x * 2], t[x * 2 + 1]);
}
int query(int x, int l, int r, int qr) {
if (r <= qr) return t[x];
int mid = (l + r) >> 1;
if (qr <= mid) return query(x * 2, l, mid, qr);
return max(t[x * 2], query(x * 2 + 1, mid + 1, r, qr));
}
public:
vector<bool> getResults(vector<vector<int>>& queries) {
int m = 0;
for (auto q : queries) {
m = max(m, q[1]);
}
++m;
set<int> st{0, m};
t.resize(2 << (32 - __builtin_clz(m)));
vector<bool> ans;
for (auto q : queries) {
int x = q[1];
auto it = st.lower_bound(x);
int pre = *prev(it);
if (q[0] == 1) {
int nxt = *it;
st.insert(x);
update(1, 0, m, x, x - pre);
update(1, 0, m, nxt, nxt - x);
}
else {
int max_gap = max(query(1, 0, m, pre), x - pre);
ans.push_back(max_gap >= q[2]);
}
}
return ans;
}
};

浙公网安备 33010602011771号