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;
    }
};
posted @ 2025-12-03 19:23  Wuyou2008  阅读(7)  评论(0)    收藏  举报