题目大意:
一个长度为 n n n的序列 a a a,对这个序列有 q q q个操作,操作类型如下:
- 将 [ l , r ] [l,r] [l,r]的 a i a_i ai异或 x x x
- 将 [ l , r ] [l,r] [l,r]的 a i a_i ai异或 ( x + ( i − l ) ) (x+(i-l)) (x+(i−l))
1 ≤ n ≤ 6 × 1 0 5 , 1 ≤ q ≤ 4 × 1 0 5 , 0 ≤ a i < 2 30 1 \le n \le 6 \times 10^5, 1 \le q \le 4 \times 10^5, 0\le a_i < 2^{30} 1≤n≤6×105,1≤q≤4×105,0≤ai<230
解题思路:(来自KeHe)
- 对于第一种操作,可以利用差分来处理
- 对于第二种操作,设 l o w b i t ( x ) = 2 k lowbit(x) = 2 ^ k lowbit(x)=2k,对于 i − l < 2 k , a ⊕ ( x + i − l ) = a ⊕ x ⊕ ( i − l ) i - l < 2 ^ k, a \oplus (x+i-l) = a \oplus x \oplus (i - l) i−l<2k,a⊕(x+i−l)=a⊕x⊕(i−l),相当于对区间 [ l , l + 2 k ) [l,l+2^k) [l,l+2k),区间异或x后再依次异或上 0 , 1 , 2 , . . . , 2 k − 1 0,1,2,...,2^k-1 0,1,2,...,2k−1,第一部分则与操作一同理,第二部分可以先打个标记,记为 b i , k b_{i,k} bi,k,执行完后: x ← x + 2 k , l ← l + 2 k x \leftarrow x + 2^k, l \leftarrow l + 2^k x←x+2k,l←l+2k, 重复上述操作直到 l + 2 k − 1 > r l+2^k - 1 > r l+2k−1>r,此时再从大到小枚举 k k k执行上述操作,填满区间 [ l , r ] [l,r] [l,r]即可
从大到小枚举k时,不用考虑跟lowbit(x)相等,因为当跟lowbit(x)相等时,在第一次的重复操作时,会l+2^k-1>r
- b i , k b_{i,k} bi,k相当于 0 , 1 , 2 , . . . , 2 k − 1 − 1 , 2 k − 1 ⊕ 0 , 2 k − 1 ⊕ 1 , . . . , 2 k − 1 ⊕ ( 2 k − 1 − 1 ) 0,1,2,...,2^{k-1}-1,2^{k-1}\oplus0,2^{k-1}\oplus1,...,2^{k-1}\oplus(2^{k-1}-1) 0,1,2,...,2k−1−1,2k−1⊕0,2k−1⊕1,...,2k−1⊕(2k−1−1),相当于标记 b i , k − 1 b_{i,k-1} bi,k−1和 b i + 2 k − 1 , k − 1 b_{i+2^{k-1},k-1} bi+2k−1,k−1,以及区间 [ i + 2 k − 1 , i + 2 k ) [i+2^{k-1},i+2^{k}) [i+2k−1,i+2k)再异或上 2 k − 1 2^{k-1} 2k−1,(要判断越界)
AC代码:
#include <bits/stdc++.h>
#define ft first
#define sd second
#define IOS ios::sync_with_stdio(false), cin.tie(0), cout.tie(0) //不能跟puts混用
#define seteps(N) fixed << setprecision(N)
#define endl "\n"
const int maxn = 1e6 + 10;
using namespace std;
typedef long long ll;
typedef double db;
typedef pair<int, int> pii;
const ll mod = 1e9 + 7;
int n, q, s[maxn], pw[20];
bitset <20> b[maxn];
void solve() {
cin >> n >> q;
int now, pre = 0;
for (int i = 1; i <= n; i++) cin >> now, s[i] = now ^ pre, pre = now;;
int op, l, r, x;
while (q--) {
cin >> 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, l = 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, l = 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 (i + pw[j - 1] > n) continue;
b[i + pw[j - 1]][j - 1].flip();
s[i + pw[j - 1]] ^= pw[j - 1];
if (i + pw[j] <= n) s[i + pw[j]] ^= pw[j - 1];
}
}
}
for (int i = 1; i <= n; i++)
s[i] ^= s[i - 1], cout << s[i] << " \n"[i == n];
}
int main() {
IOS;
pw[0] = 1;
for (int i = 1; i <= 19; i++) pw[i] = pw[i - 1] * 2;
solve();
return 0;
}