题意
n个数,m次询问,每次问[L,R]区间内又多少个(i,j)满足a[i]^a[i+1]...^a[j]==k?
思路
求前缀异或和,那么pre[L-1]^pre[R]=a[L]^...^a[R]。假设pre[L-1]^pre[R]=k,则有pre[L-1]=pre[R]^k。所以我们用cnt[x]表示当前区间内异或 k 为 x 的值有多少个。
然后就可以用莫队了。区间增加1,对答案的贡献增加cnt[a[x]^k]的贡献,同时cnt[a[x]^k]++。
区间减少1,对答案的贡献减少了cnt[a[x]^k]的贡献,同时cnt[a[x]^k]--。
由于我们用的是前缀和,所以当我们L区间变化的时候,对答案的贡献增加或减少的是 pre[L-1]^k 的值,一定要注意。
还有就是什么都不选的时候异或和为0,所以初始化cnt[0]=1。
PS:
有点SB了,++,--用的导致代码难懂。。。
a[(l++)-1],先把a[l-1]传过去,然后再l++。
a[(--l)-1],先l--,然后再把a[l-1]传过去。
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 1e6+5;
typedef long long LL;
int n, m, k, a[MAXN];
struct Query
{
int l, r, id;
LL ans;
}q[MAXN];
int block, pos[MAXN], l, r;
LL cnt[MAXN*10], ans;
void update(int x, int d)
{
if (d == 1) ans += cnt[x^k], cnt[x]++;
if (d == -1) cnt[x]--, ans -= cnt[x^k];
}
int main()
{
scanf("%d%d%d", &n, &m, &k);
block = sqrt(n);
for (int i = 1; i <= n; i++)
{
scanf("%d", &a[i]);
a[i] ^= a[i-1];
pos[i] = (i-1)/block+1;
}
for (int i = 0; i < m; i++) scanf("%d%d", &q[i].l, &q[i].r), q[i].id = i;
sort(q, q+m, [](Query A, Query B){ return pos[A.l]!=pos[B.l]?A.l<B.l:A.r<B.r; });
cnt[0] = 1;
l = 1, r = 0, ans = 0;
for (int i = 0; i < m; i++)
{
while (l < q[i].l) update(a[(l++)-1], -1);
while (l > q[i].l) update(a[(--l)-1], 1);
while (r < q[i].r) update(a[++r], 1);
while (r > q[i].r) update(a[r--], -1);
q[i].ans = ans;
}
sort(q, q+m, [](Query A, Query B){ return A.id < B.id; });
for (int i = 0; i < m; i++) printf("%lld\n", q[i].ans);
return 0;
}
/*
6 2 3
1 2 1 1 0 3
1 6
3 5
*/