考虑异或差分 。操作 1 直接
即可。考虑操作 2 ,设
,则对于
,相当于对于区间
,区间异或
后再依次异或上
,第一部分与操作 1 同理,第二部分可以直接先打个标记,记为
,执行完后
。重复上述操作直到
,此时再从大到小枚举
执行上述操作直到填满区间
即可。处理完所有操作后考虑处理
,从大到小枚举
,实际上
相当于
,相当于标记
和
,然后区间
异或上
,注意判断是否越界。
#include <bits/stdc++.h>
using namespace std;
const int N = 6e5 + 5;
int n, q, pw[20], s[N];
bitset<20> b[N];
inline void Solve() {
int x, y = 0;
for (int i = 1; i <= n; ++i)
scanf("%d", &x), s[i] = x ^ y, y = x;
for (int op, l, r; q--;) {
scanf("%d%d%d%d", &op, &l, &r, &x);
if (!op) {
s[l] ^= x, s[r + 1] ^= x;
continue;
}
for (int i = 0; i <= 19; ++i)
if (x & pw[i] && l + pw[i] - 1 <= r)
b[l][i].flip(), s[l] ^= x, s[l += pw[i]] ^= x, x += pw[i];
for (int i = 19; i >= 0; --i)
if (l + pw[i] - 1 <= r)
b[l][i].flip(), s[l] ^= x, s[l += pw[i]] ^= x, x += pw[i];
}
for (int i = 1; i <= n; ++i)
for (int j = 19; j >= 1; --j)
if (b[i][j]) {
b[i][j - 1].flip();
if ((x = i + pw[j - 1]) > n)
continue;
b[x][j - 1].flip(), s[x] ^= pw[j - 1];
if (i + pw[j] <= n)
s[i + pw[j]] ^= pw[j - 1];
}
for (int i = 1; i <= n; ++i)
printf("%d%c", s[i] ^= s[i - 1], " \n"[i == n]);
}
int main() {
pw[0] = 1;
for (int i = 1; i <= 19; ++i)
pw[i] = pw[i - 1] << 1;
while (~scanf("%d%d", &n, &q))
Solve();
return 0;
} 
京公网安备 11010502036488号