bzoj 1230 lites 开关灯(线段树区间异或)
题目大意
略
解题思路
区间异或,与其他操作不太一样,要考虑标记下传的时候子区间的标记的情况。
代码
const int maxn = 1e5+10;
int n, m;
struct Tree {
int l, r, sum, lz;
} tree[maxn<<2];
inline void push_up(int rt) {
tree[rt].sum = tree[rt<<1].sum+tree[rt<<1|1].sum;
}
inline void push_down(int rt) {
if (tree[rt].lz==1) {
int len = tree[rt].r-tree[rt].l+1;
tree[rt<<1].sum = (len-(len>>1))-tree[rt<<1].sum;
tree[rt<<1|1].sum = (len>>1)-tree[rt<<1|1].sum;
if (tree[rt<<1].lz==-1) tree[rt<<1].lz = 1;
else tree[rt<<1].lz ^= 1;
if (tree[rt<<1|1].lz==-1) tree[rt<<1|1].lz = 1;
else tree[rt<<1|1].lz ^= 1;
}
tree[rt].lz = -1;
}
void build(int rt, int l, int r) {
tree[rt].l = l, tree[rt].r = r; tree[rt].lz = -1; tree[rt].sum = 0;
if (l==r) return;
int mid = (l+r)>>1;
build(rt<<1, l, mid);
build(rt<<1|1, mid+1, r);
}
void update(int rt, int l, int r) {
if (tree[rt].l>=l && tree[rt].r<=r) {
int len = tree[rt].r-tree[rt].l+1;
tree[rt].sum = len-tree[rt].sum;
if (tree[rt].lz==-1) tree[rt].lz = 1;
else tree[rt].lz ^= 1;
return;
}
push_down(rt);
int mid = (tree[rt].l+tree[rt].r)>>1;
if (l<=mid) update(rt<<1, l, r);
if (r>mid) update(rt<<1|1, l, r);
push_up(rt);
}
int ask(int rt, int l, int r) {
if (tree[rt].l>=l && tree[rt].r<=r) return tree[rt].sum;
int sum = 0;
int mid = (tree[rt].l+tree[rt].r)>>1;
push_down(rt);
if (l<=mid) sum += ask(rt<<1, l, r);
if (r>mid) sum += ask(rt<<1|1, l, r);
push_up(rt);
return sum;
}
int main() {
cin >> n >> m;
build(1, 1, n);
for (int i = 0, a, b, c; i<m; ++i) {
scanf("%d%d%d", &a, &b, &c);
if (a) printf("%d\n", ask(1, b, c));
else update(1, b, c);
}
return 0;
}