题意:给你n个数,再给定m个询问和一个数k,每个询问是一个区间 [ l ,r ]
问这个区间中有多少个i j 满足a[i]^a[i+1]^...^a[j]==k;
刚开始得知是莫队算法,去了解了下这个算法然后开始写,发现还是不知道怎么处理
最后是照着别人代码写的,还看了好久,,最后还是理解了 自己还是弱啊。。(不过对异或和这个算法也更了解了)
#include<bits/stdc++.h>
using namespace std;
#define N 1000005
struct lx{
int l,r,id;
}p[N];
int a[N],num[N*2],b[N];
long long ans[N];
int n,m,k,sq;
bool cmp(lx a,lx b){
if(a.l/sq!=b.l/sq)return a.l/sq<b.l/sq;
else return a.r<b.r;
}
void work(){
memset(num,0,sizeof(num));
int left=1,right=0;
long long cnt=0;
for(int i=0;i<m;++i){
while(right<p[i].r){ //
right++; // b[i]为前缀和,求a[l]^a[l+1]^...^a[r]==k即求b[l-1]^b[r]==k即b[r]^k==b[l-1];(由a^a=0可以得到)
cnt+=num[b[right]^k]; // num[]数组表示right之前有几个i是满足b[right]^k==b[i-1]的;
num[b[right]]++; // 这样cnt直接加上num[b[right]^k]就是当前left->right的答案;
} // 再更新num[b[right]];
while(right>p[i].r){
num[b[right]]--;
cnt-=num[b[right]^k];
right--;
}
while(left>p[i].l-1){
left--;
cnt+=num[b[left]^k];
num[b[left]]++;
}
while(left<p[i].l-1){
num[b[left]]--;
cnt-=num[b[left]^k];
left++;
}
ans[p[i].id]=cnt;
}
}
int main(){
memset(b,0,sizeof(b));
scanf("%d%d%d",&n,&m,&k);
for(int i=1;i<=n;++i){
scanf("%d",&a[i]);
b[i]=b[i-1]^a[i];
}
sq=(int)sqrt(n);
for(int i=0;i<m;++i){
scanf("%d%d",&p[i].l,&p[i].r);
p[i].id=i;
}
sort(p,p+m,cmp);
work();
for(int i=0;i<m;++i){
printf("%I64d\n",ans[i]);
}
}
本文介绍了一种使用莫队算法解决特定区间异或查询问题的方法。通过实例讲解了如何利用前缀和及哈希表优化查询效率,并提供了一份完整的C++实现代码。
515

被折叠的 条评论
为什么被折叠?



