思路是分块,记一个前缀和和连续块答案,然后统计贡献。
#1 错在了第四次询问:
50 1275 3
5 7 4 5 6 8 0 6 4 6 7 2 2 3 0 5 5 6 5 4 7 2 0 1 3 5 3 4 7 8 2 3 2 7 6 6 2 0 8 3 6 1 8 4 3 1 5 6 4 1
38 39
29 30
7 36
26 43
30 35
1 25
15 30
18 22
24 32
5 34
3 23
11 19
25 30
12 30
33 37
12 48
10 12
23 28
12 21
9 44
11 11
36 50
22 43
36 44
11 32
17 21
33 36
31 36
5 44
……
#include<bits/stdc++.h>
#define LL long long
using namespace std;
const int N=1e3+10,M=4e2+10;
int n,m,K,len,cnt,Max;
int a[N],p[N][M],f[M][M],val[M][N],st[M],ed[M],bar[N];
void init(){
int w[N*2]={};
scanf("%d%d%d",&n,&m,&K);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]),a[i]^=a[i-1],Max=max(Max,a[i]);
len=sqrt(n);cnt=n/len+bool(n%len);ed[0]=-1;
for(int i=1;i<=cnt;i++){
for(int j=0;j<=Max;j++)p[j][i]=p[j][i-1];
st[i]=ed[i-1]+1;ed[i]=min(i*len,n);
for(int j=st[i];j<=ed[i];j++)p[a[j]][i]++,bar[j]=i;
}
for(int i=1;i<=cnt;i++){
memset(w,0,sizeof(w));w[0]=(i==1);
for(int j=i;j<=cnt;j++){
f[i][j]=f[i][j-1];
for(int k=st[j];k<=ed[j];k++)f[i][j]+=w[K^a[k]],w[a[k]]++;
}
}
for(int i=1;i<=cnt;i++){
for(int j=st[i];j<=ed[i];j++)w[j]=a[j];
sort(w+st[i],w+ed[i]+1);
for(int j=1;j<=Max;j++)val[i][j]=5e2+1;
val[i][w[st[i]]]=1;
for(int j=st[i]+1;j<=ed[i];j++)if(w[j]!=w[j-1])val[i][w[j]]=val[i][w[j-1]]+1;
}
return;
}
LL query(int x,int y){
int l=bar[--x],r=bar[y],w[M]={};LL ret=f[l+1][r-1];
if(l==r){
for(int i=x;i<=y;i++)
ret+=w[val[l][K^a[i]]],w[val[l][a[i]]]++;
return ret;
}
for(int i=x;i<=ed[l];i++)
ret+=w[val[l][K^a[i]]],w[val[l][a[i]]]++;
for(int i=st[r];i<=y;i++)
ret+=w[val[l][K^a[i]]],w[val[l][a[i]]]++;
for(int i=x;i<=ed[l];i++)ret+=p[K^a[i]][r-1]-p[K^a[i]][l];
for(int i=st[r];i<=y;i++)ret+=p[K^a[i]][r-1]-p[K^a[i]][l];
return ret;
}
signed main(){
init();
// for(int i=1;i<=n;i++)printf("%d ",a[i]);puts("");
// for(int i=1;i<=cnt;i++)
// {for(int j=st[i];j<=ed[i];j++)printf("%d ",val[i][a[j]]);printf("|");}puts("");
for(int i=1;i<=m;i++){
int L,R;
scanf("%d%d",&L,&R);
printf("%lld\n",query(L,R));
}
system("pause");
return 0;
}