思路:
如何求出任意一段的区间异或值是个问题。

如果a[i] ^ a[i+1] ^ … ^ a[j] = k 相当于 s[i-1]^s[j]==k, s[]为异或前缀和,那么就是求一个区间的前缀和s[i] ^ s[j]的对数。

莫队转移一下就行了。

WA点:区间前缀和可以比k大, 保存前缀和的数字应该开大一点。

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
//由块号寻找第一个块元素的下标
#define LL(x) ((x-1)*Len+1)

const int maxn=1<<20;

struct node
{
    int L, R, k;
}q[maxn];

int pos[maxn];
LL ans[maxn];
LL flag[maxn];//保存当前区间前缀和的个数
int a[maxn];

bool cmp(node a, node b)
{
    if(pos[a.L]==pos[b.L])
    {
        return a.R<b.R;
    }

    return pos[a.L]<pos[b.L];
}

int n, m, k, Len;
int L=1, R=0;
LL ANS=0;

void add(int x)
{
    //先加防止 a[x]^k==a[x] 重复加上
    ANS+=flag[a[x]^k];
    flag[a[x]]++;
}

void del(int x)
{
    //先减防止 a[x]^k==a[x] 重复减去
    flag[a[x]]--;
    ANS-=flag[a[x]^k];
}

int main()
{
    scanf("%d%d%d",&n,&m,&k);
    Len=sqrt(n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
        a[i]=a[i]^a[i-1];
        pos[i]=i/Len;
    }

    for(int i=1;i<=m;i++)
    {
        scanf("%d%d",&q[i].L,&q[i].R);
        q[i].k=i;
    }

    sort(q+1, q+1+m, cmp);
    flag[0]=1;//为了统计a[i]=k

    for(int i=1;i<=m;i++)
    {
        while(L<q[i].L)
        {
            del(L-1);
            L++;
        }
        while(L>q[i].L)
        {
            L--;
            add(L-1);
        }
        while(R<q[i].R)
        {
            R++;
            add(R);
        }
        while(R>q[i].R)
        {
            del(R);
            R--;
        }
        ans[q[i].k]=ANS;
    }
    for(int i=1;i<=m;i++)
    {
        cout<<ans[i]<<endl;
    }

    return 0;
}