莫队算法就是现将上所有的点分成sqrt(n)块,然后将要查询的区间离线起来,然后进行对[L,R]变到[L - 1,R] 、或者[L + 1,R],[L,R - 1],[L,R + 1]进行O(1)的变换。
莫队算法是优雅的暴力,复杂度O(nlogn)。
题意:给出一个一个数列,然后查询在给出区间的异或值等于k的子区间的个数。
思路:先对区间进行去前缀和处理,然后区间[L,R]的异或值为sum[R] ^sum[L - 1];然后剩下来的就是进行L,R的转移了。
#include<bits/stdc++.h>
using namespace std;
#define clr(x,y) memset(x,y,sizeof x)
typedef long long ll;
const int maxn = 2e6 + 10;
int a[maxn],pos[maxn],sum[maxn];
ll num[maxn];
struct Node{int L,R,id;}q[maxn];
bool cmp(Node p1,Node p2)
{
return pos[p1.L] == pos[p2.L] ? p1.R < p2.R : pos[p1.L] < pos[p2.L];
}
ll Ans;
int n,m,k;
void add(int x)
{
Ans += num[sum[x]^k];
num[sum[x]] ++;
}
void del(int x)
{
num[sum[x]] --;
Ans -= num[sum[x]^k];
}
ll ans[maxn];
int main()
{
// freopen("in.txt","r",stdin);
while( ~ scanf("%d%d%d",&n,&m,&k))
{
clr(num,0);sum[0] = 0;num[0] = 1;
int ss = sqrt(n);
for(int i = 1;i <= n;i ++)scanf("%d",&a[i]),pos[i] = i / ss,sum[i] = sum[i - 1] ^ a[i];
for(int i = 1; i <= m;i ++)scanf("%d%d",&q[i].L,&q[i].R),q[i].id = i;
sort(q + 1,q + m + 1,cmp);
int l = 1,r = 0;
Ans = 0;
for(int i = 1;i <= m;i ++)
{
while(l > q[i].L)
{
l --;
add(l - 1);
}
while(l < q[i].L)
{
del(l - 1);
l ++;
}
while(r > q[i].R)
{
del(r --);
}
while(r < q[i].R)
{
add(++ r);
}
ans[q[i].id] = Ans;
}
for(int i = 1;i <= m;i ++)
{
printf("%lld\n",ans[i]);
}
}
return 0;
}