题目
思路
嗯,裸的莫队。
复习莫队,离线将询问按左端点所在的块和右端点排序,然后求出[l,r]可以O(1)扩展一步。时间复杂度O(n^1.5)。
这题就是求异或前缀和,然后我们发现扩张一个格子可以计算贡献,并在桶里加或减。注意这里的左端点要减1,莫队注意先搞右再搞左,代码还是写得很优雅的。
代码
#include <bits/stdc++.h>
#define maxn 100100
using namespace std;
int n, m, k, block, answer;
int a[maxn], ans[maxn], cnt[maxn];
struct Query{
int l, r, id;
bool operator < (const Query& OTHER) const{
if((l-1) / block == (OTHER.l-1) / block) return r < OTHER.r;
return (l-1) / block < (OTHER.l-1) / block;
}
}q[maxn];
void Insert(int x){
cnt[x] ++;
answer += cnt[x^k];
}
void Remove(int x){
answer -= cnt[x^k];
cnt[x] --;
}
int main(){
scanf("%d%d%d", &n, &m, &k);
block = (int)sqrt(n);
for(int i = 1; i <= n; i++) scanf("%d", &a[i]);
for(int i = 2; i <= n; i++) a[i] ^= a[i-1];
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);
int l = 1, r = 0;
for(int i = 1; i <= m; i++){
while(r < q[i].r) Insert(a[++r]);
while(r > q[i].r) Remove(a[r--]);
while(l < q[i].l-1) Remove(a[l++]);
while(l > q[i].l-1) Insert(a[--l]);
ans[q[i].id] = answer;
}
for(int i = 1; i <= m; i++) printf("%d\n", ans[i]);
return 0;
}