题目给出若干查询,需要询问一个区间内有多少对 i , j i,j i,j满足 a i ⊕ a i + 1 . . . ⊕ a j = k a_i \oplus a_{i+1}...\oplus a_j=k ai⊕ai+1...⊕aj=k,因为是区间异或,考虑前缀异或的性质,完全可以根据前缀异或 p r e [ r ] ⊕ p r e [ l − 1 ] pre[r] \oplus pre[l-1] pre[r]⊕pre[l−1]求出区间 [ l , r ] [l,r] [l,r]的异或值
然后问题就变成了在一个区间内,有多少对 ( l , r ) . s t . p r e [ r ] ⊕ p r e [ l − 1 ] = k (l,r)~~.st.~~pre[r] \oplus pre[l-1]=k (l,r) .st. pre[r]⊕pre[l−1]=k,但是这样仍然不好求,或者这样,在区间内对于某个 p r e [ x ] pre[x] pre[x],有多少个 p r e [ y ] ⊕ k = p r e [ x ] pre[y] \oplus k = pre[x] pre[y]⊕k=pre[x],显然变成了区间的计数问题,这样就是裸的莫队了
易错点:
- 在对区间 [ l , r ] [l,r] [l,r]统计个数时,因为前缀异或的缘故,显然最多得到的异或区间为 p r e [ r ] ⊕ p r e [ l ] ⟹ [ l + 1 , r ] pre[r] \oplus pre[l] \Longrightarrow [l+1,r] pre[r]⊕pre[l]⟹[l+1,r],那么就要再加上 c n t [ a [ l − 1 ] ] cnt[a[l-1]] cnt[a[l−1]]的个数
- 因为任何数和0异或都不变,注意到 k k k可能为0,也就是 k ⊕ a [ p o s ] = a [ p o s ] k \oplus a[pos] = a[pos] k⊕a[pos]=a[pos]。那么在删除时,需要先 c n t [ a [ p o s ] ] − − cnt[a[pos]]-- cnt[a[pos]]−−再从答案减去;否则会多减一个(这里想了好久才想通,也解释不了那么多了,大部分博客都没解释的)
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 2e6 + 10;
struct node {
int l, r, id, pos;
bool operator<(const node &p) const {
return pos == p.pos ? r < p.r : pos < p.pos;
}
} q[maxn];
ll a[maxn], pre[maxn], cnt[maxn], ans[maxn], tot;
int n, m, k;
inline void add(int pos) {
tot += cnt[pre[pos] ^ k];
cnt[pre[pos]]++;
}
inline void del(int pos) {
cnt[pre[pos]]--;
tot -= cnt[pre[pos] ^ k];
}
void solve() {
int l = 1, r = 0;
for (int i = 1; i <= m; i++) {
int ql = q[i].l, qr = q[i].r;
while (l < ql) del(l++);
while (l > ql) add(--l);
while (r < qr) add(++r);
while (r > qr) del(r--);
ans[q[i].id] = tot + cnt[k ^ pre[l - 1]];
}
for (int i = 1; i <= m; i++) cout << ans[i] << "\n";
}
int main() {
ios_base::sync_with_stdio(0), cin.tie(0), cout.tie(0);
cin >> n >> m >> k;
for (int i = 1; i <= n; i++) {
cin >> a[i];
pre[i] = pre[i - 1] ^ a[i];
}
int sz = sqrt(n);
for (int i = 1; i <= m; i++) {
cin >> q[i].l >> q[i].r;
q[i].id = i;
q[i].pos = (q[i].l - 1) / sz + 1;
}
sort(q + 1, q + 1 + m);
solve();
return 0;
}