题目链接:Codeforces-617E-XOR and Favorite Number
莫队算法用于处理区间无修改查询问题。其思想是通过离线组织询问的顺序来降低复杂度。使用莫队算法的前提条件是当我们知道 [L,R] 的答案时,能 O(1) 算出 [L,R+1] , [L,R−1] , [L+1,R] , [L−1,R] 的答案。
基本思路是根据下标将长度为
n
的区间分成
对于每个询问
[Li,Ri]
将其首先根据
Li
所处于的块编号进行排序,其次对于
Ri
排序。
这样,当我们从询问
[Li,Ri]
跳转到询问
[Li+1,Ri+1]
时:
1.若
Li
与
Li+1
处于不同块,则
Ri
跳转到
Ri+1
的复杂度最高是
O(n)
。因为只有
n√
块,所以这种情况最多出现
n√
次。复杂度是
O(n32)
。
2.若
Li
与
Li+1
处于相同块,则
Li
跳转到
Li+1
的复杂度最高是
O(n√)
,这种情况出现次数为
n−n√≈n
,所以总的复杂度是
O(n32)
。
因此总的复杂度是
O(n32)
。
对于这道题,我们设置异或前缀和:
所以区间异或和:
所以每当区间延伸一个单位时,答案只需加上满足 Xor(l,r)==k 的个数,用一个数组记录区间中所有pre出现的次数即可。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5+7;
const int maxv=1<<20;
int pre[maxn],pos[maxn];
int cnt[maxv],k;
ll ans[maxn];
int L=1,R=0;
ll Ans;
struct Query
{
int l,r,id;
bool operator < (const Query &b) const
{
if(pos[l]==pos[b.l]) return r<b.r;
return pos[l]<pos[b.l];
}
};
Query Q[maxn];
void add(int x)
{
Ans+=cnt[pre[x]^k];
++cnt[pre[x]];
}
void del(int x)
{
--cnt[pre[x]];
Ans-=cnt[pre[x]^k];
}
int main()
{
ios::sync_with_stdio(false);
int n,m;
cin>>n>>m>>k;
int sz=sqrt(n);
for(int i=1;i<=n;i++)
{
cin>>pre[i];
pre[i]^=pre[i-1];
pos[i]=i/sz;
}
for(int i=1;i<=m;i++)
{
cin>>Q[i].l>>Q[i].r;
Q[i].id=i;
}
sort(Q+1,Q+m+1);
Ans=0;
cnt[0]=1;
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);
--R;
}
while(R<Q[i].r)
{
++R;
add(R);
}
ans[Q[i].id]=Ans;
}
for(int i=1;i<=m;i++)
cout << ans[i] << endl;
return 0;
}