考虑异或差分 。操作 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; }