题意:
给出n个数的序列,给出m个区间[L,R]的询问,问在[L,R]中有多少段子区间的异或和等于k。
思路:
莫队算法,先保存前缀异或和,然后对于每次从[L,R]转移到[L,R+1]只需要O(1)的时间,只需要知道sum[R^k]有多少即可,因为每个数都不大,可以直接开一个数组保存。另外这题的莫队需要分块处理,否则还是T。
代码:
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
#include <cmath>
using namespace std;
typedef long long ll;
const int MAXN = 1e5 + 10;
const int MAXA = 2e6 + 10;
ll cur;
int n, m, k;
int cnt[MAXA], sum[MAXN], p[MAXN];
ll ans[MAXN];
void add(int pos) {
cur += cnt[sum[pos] ^ k];
cnt[sum[pos]]++;
}
void del(int pos) {
cnt[sum[pos]]--;
cur -= cnt[sum[pos] ^ k];
}
struct Query {
int l, r, id;
bool operator < (const Query &rhs) const {
return p[l] == p[rhs.l] ? r < rhs.r : p[l] < p[rhs.l];
}
}q[MAXN];
int main() {
scanf("%d%d%d", &n, &m, &k);
for (int i = 1; i <= n; i++) {
scanf("%d", &sum[i]);
sum[i] ^= sum[i - 1];
}
int block = ceil(sqrt(n));
for (int i = 1; i <= n; i++) p[i] = (i - 1) / block;
for (int i = 1; i <= m; i++) {
scanf("%d%d", &q[i].l, &q[i].r);
q[i].id = i;
}
sort (q + 1, q + 1 + m);
cnt[0] = 1;
add(1);
int l = 1, r = 1;
for (int i = 1; i <= m; i++) {
while (r > q[i].r) {
del(r);
r--;
}
while (r < q[i].r) {
++r;
add(r);
}
while (l > q[i].l) {
--l;
add(l - 1);
}
while (l < q[i].l) {
del(l - 1);
l++;
}
ans[q[i].id] = cur;
}
for (int i = 1; i <= m; i++)
printf("%lld\n", ans[i]);
return 0;
}