📅  最后修改于: 2023-12-03 15:28:37.882000             🧑  作者: Mango
有 $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
类,然后实现了其中的 pushUp
、pushDown
、build
、update
和 query
函数。在 executeOperations
函数中,我们首先构造了一个 SegmentTree
的对象,然后我们在进行 ops
中每一个操作时,使用 SegmentTree
进行对应的修改或查询操作,最终将每一个查询操作查询到的答案加到 res 中,并返回 res 即可。