📜  门| GATE CS 2018 |第 38 题(1)

📅  最后修改于: 2023-12-03 15:28:37.882000             🧑  作者: Mango

门 | GATE CS 2018 | 第 38 题

题目描述

有 $n$ 个房间排成一排,最开始每个房间都是关闭的。 现在你需要执行 $q$ 次操作,每次操作要么开启房间,要么关闭房间,要么翻转房间(如果该房间已开启,则关闭它,如果该房间已关闭,则开启它)。 每次操作后,输出开启的房间数量。

思路分析

对于此题,我们可以使用线段树进行解决。具体地,我们可以用线段树维护每一个区间中开启的房间数量,然后修改操作时进行区间加减或者区间取反。

代码实现

下面是 C++ 中使用线段树实现此题的代码片段。

const int MAXN = 2097152;

class SegmentTree {
    private:
    int n;
    int* sum = new int[MAXN << 2];
    bool* lazy = new bool[MAXN << 2];
    public:
    SegmentTree(int n) {
        this -> n = n;
        memset(sum, 0, sizeof(int) * (n << 2));
        memset(lazy, false, sizeof(bool) * (n << 2));
    }
    void pushUp(int rt) {
        sum[rt] = sum[rt << 1] + sum[rt << 1 | 1];
    }
    void pushDown(int rt, int ln, int rn) {
        if (lazy[rt]) {
            lazy[rt << 1] ^= 1;
            lazy[rt << 1 | 1] ^= 1;
            sum[rt << 1] = ln - sum[rt << 1];
            sum[rt << 1 | 1] = rn - sum[rt << 1 | 1];
            lazy[rt] = false;
        }
    }
    void build(int rt, int l, int r) {
        if (l == r) {
            sum[rt] = 0;
            return;
        }
        int mid = (l + r) >> 1;
        build(rt << 1, l, mid);
        build(rt << 1 | 1, mid + 1, r);
        pushUp(rt);
    }
    void update(int rt, int l, int r, int ql, int qr) {
        if (ql <= l && qr >= r) {
            lazy[rt] ^= 1;
            sum[rt] = r - l + 1 - sum[rt];
            return;
        }
        int mid = (l + r) >> 1;
        pushDown(rt, mid - l + 1, r - mid);
        if (ql <= mid) update(rt << 1, l, mid, ql, qr);
        if (qr > mid) update(rt << 1 | 1, mid + 1, r, ql, qr);
        pushUp(rt);
    }
    int query(int rt, int l, int r, int ql, int qr) {
        if (ql <= l && qr >= r) return sum[rt];
        int mid = (l + r) >> 1, res = 0;
        pushDown(rt, mid - l + 1, r - mid);
        if (ql <= mid) res += query(rt << 1, l, mid, ql, qr);
        if (qr > mid) res += query(rt << 1 | 1, mid + 1, r, ql, qr);
        return res;
    }
};

class Solution {
    public:
    vector<int> executeOperations(int n, vector<vector<int>>& ops) {
        SegmentTree* tree = new SegmentTree(n);
        vector<int> res;
        for (int i = 0; i < ops.size(); i++) {
            int op = ops[i][0], l = ops[i][1], r = ops[i][2];
            switch (op) {
                case 1: {
                    tree -> update(1, 1, n, l + 1, r + 1);
                    break;
                }
                case 2: {
                    tree -> update(1, 1, n, l + 1, r + 1);
                    break;
                }
                case 3: {
                    res.push_back(tree -> query(1, 1, n, l + 1, r + 1));
                    break;
                }
            }
        }
        return res;
    }
};

在上面的代码中,我们首先定义了一个 SegmentTree 类,然后实现了其中的 pushUppushDownbuildupdatequery 函数。在 executeOperations 函数中,我们首先构造了一个 SegmentTree 的对象,然后我们在进行 ops 中每一个操作时,使用 SegmentTree 进行对应的修改或查询操作,最终将每一个查询操作查询到的答案加到 res 中,并返回 res 即可。