牛客小白月赛9-红球进黑洞(异或线段树)
题意:
操作 \(1\):求 \([l,r]\) 区间和。
操作 \(2\):区间 \([l,r]\) 的数异或上\(k\)。
分析:
对区间进行位运算是没啥公式的,所以要考虑对数的每一位建线段树,记录每一位 \(1\) 出现的次数。询问的时候求出每一位的贡献即可。
线段树维护的是每一位 \(1\) 的出现次数。
区间异或:首先如果 \(k\) 的 \(i\) 位为 \(0\),则异或值不变,否则异或 \(i\) 位的区间 \([l,r]\) 相当于将这个区间的 \(0\) 变成 \(1\),\(1\)变成 \(0\)。
区间或:或上某一位1才有意义
区间与:与上某一位0才有意义
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 1e5 + 5;
const int mod = 1e9 + 7;
int n, q, w[N];
int seg[N << 2][19], lazy[N << 2][19];
int opt, res, x, y, k;
LL ans, base;
void build(int rt, int l, int r, int o) {
if (l == r) {
seg[rt][o] += ((w[l] >> o) & 1);
return ;
}
int mid = l + r >> 1;
build(rt << 1, l, mid, o);
build(rt << 1 | 1, mid + 1, r, o);
seg[rt][o] = seg[rt << 1][o] + seg[rt << 1 | 1][o];
}
void pushdown(int rt, int l, int r, int mid, int o) {
if (lazy[rt][o]) {
lazy[rt << 1][o] ^= 1;
lazy[rt << 1 | 1][o] ^= 1;
seg[rt << 1][o] = (mid - l + 1) - seg[rt << 1][o];
seg[rt << 1 | 1][o] = (r - mid) - seg[rt << 1 | 1][o];
lazy[rt][o] ^= 1;
}
}
void update(int rt, int l, int r, int ql, int qr, int o) {
if (l >= ql && r <= qr) {
seg[rt][o] = (r - l + 1) - seg[rt][o];
lazy[rt][o] ^= 1;
return ;
}
int mid = l + r >> 1;
pushdown(rt, l, r, mid, o);
if (ql <= mid) update(rt << 1, l, mid, ql, qr, o);
if (qr > mid) update(rt << 1 | 1, mid + 1, r, ql, qr, o);
seg[rt][o] = seg[rt << 1][o] + seg[rt << 1 | 1][o];
}
int query(int rt, int l, int r, int ql, int qr, int o) {
if (l >= ql && r <= qr) {
return seg[rt][o];
}
int mid = l + r >> 1, ans = 0;
pushdown(rt, l, r, mid, o);
if (ql <= mid) ans += query(rt << 1, l, mid, ql, qr, o);
if (qr > mid) ans += query(rt << 1 | 1, mid + 1, r, ql, qr, o);
return ans;
}
int main() {
scanf("%d %d", &n, &q);
for (int i = 1; i <= n; i++) scanf("%d", w + i);
for (int i = 0; i <= 17; i++) build(1, 1, n, i);
while (q--) {
scanf("%d", &opt);
if (opt == 1) {
scanf("%d %d", &x, &y);
ans = 0, base = 1;
for (int i = 0; i <= 17; i++) {
ans += 1LL * base * query(1, 1, n, x, y, i);
base <<= 1;
}
printf("%lld\n", ans);
} else {
scanf("%d %d %d", &x, &y, &k);
for (int i = 0; i <= 17; i++) {
res = ((k >> i) & 1);
if (res) update(1, 1, n, x, y, i);
}
}
}
return 0;
}