题目链接
题解
来做一下水题来掩饰ZJOI2019考炸的心情QwQ。
很明显可以线段树。
维护两个值,\(Lazy\)懒标记表示当前区间是否需要翻转,\(s\)表示区间还有多少灯是亮着的。
那么每一次翻转,\(s\)就变成了\(n-s\),\(n\)表示区间内所有灯的数量。
线段树维护一下就可以了。
代码
#include <bits/stdc++.h>
using namespace std;
const int N = 100000 + 6;
int n, m;
namespace seg {
#define lc (nod << 1)
#define rc (nod << 1 | 1)
struct node {
int l, r, tg, s;
} tr[N << 2];
void pushup(int nod) { tr[nod].s = tr[lc].s + tr[rc].s; }
void pushdown(int nod, int l, int r) {
if (!tr[nod].tg) return;
int mid = (l + r) >> 1;
tr[lc].s = (mid - l + 1) - tr[lc].s; tr[lc].tg ^= 1;
tr[rc].s = (r - mid) - tr[rc].s; tr[rc].tg ^= 1;
tr[nod].tg = 0;
}
void build(int nod, int l, int r) {
tr[nod].l = l, tr[nod].r = r, tr[nod].s = 0, tr[nod].tg = 0;
if (l == r) return;
int mid = (l + r) >> 1;
build(lc, l, mid); build(rc, mid + 1, r);
pushup(nod);
}
void upd(int nod, int l, int r, int ql, int qr) {
if (ql <= l && r <= qr) {
tr[nod].s = (r - l + 1) - tr[nod].s;
tr[nod].tg ^= 1;
return;
}
int mid = (l + r) >> 1;
pushdown(nod, l, r);
if (ql <= mid) upd(lc, l, mid, ql, qr);
if (qr > mid) upd(rc, mid + 1, r, ql, qr);
pushup(nod);
}
int query(int nod, int l, int r, int ql, int qr) {
if (ql <= l && r <= qr) return tr[nod].s;
int mid = (l + r) >> 1, res = 0;
pushdown(nod, l, r);
if (ql <= mid) res += query(lc, l, mid, ql, qr);
if (qr > mid) res += query(rc, mid + 1, r, ql, qr);
return res;
}
}
int main() {
scanf("%d%d", &n, &m);
seg::build(1, 1, n);
for (int i = 1; i <= m; i ++) {
int opt, x, y; scanf("%d%d%d", &opt, &x, &y);
if (opt == 0) seg::upd(1, 1, n, x, y);
else printf("%d\n", seg::query(1, 1, n, x, y));
}
return 0;
}