題目鏈接: https://codeforces.com/contest/617/problem/E
題意:
長爲 的數組 ,和 個查詢,每次查詢要求出區間 中有多少 個子區間使得該區間內的異或和爲 。
做法:
因爲我們要快速求得一個區間 中的異或和,所以我們大可以先把所有的值 變成 ^ 這樣我們就可以在 的時間裏得到區間的和,即 ^ 。
然後每次對邊界進行加減就變得很快,莫隊的思想就出現了。
比如我們要將右區間變大,那麼對於原來的區間 中的影響會先保存在數組 裏,若加入 之後存在 個區間 ,那麼一定有 ^ ,因爲 是前綴異或和, ^ 其實就是區間 的異或和,所以是可以直接表示的。
代碼
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
typedef long long ll;
const int maxn=100005;
const int MAX=(1<<20)+5;
ll num[MAX],ans[maxn],tmp;
int n,m,k,a[maxn];
struct node{
int l,r,id,blo;
}e[maxn];
bool cmp(node a,node b){
if(a.blo==b.blo) return a.r<b.r;
return a.blo<b.blo;
}
void add(int p){
tmp+=num[a[p]^k];
num[a[p]]++;
}
void del(int p){
num[a[p]]--;
tmp-=num[a[p]^k];
}
int main(){
scanf("%d%d%d",&n,&m,&k);
int sz=sqrt(n+1);
rep(i,1,n){
scanf("%d",&a[i]);
a[i]^=a[i-1];
}
rep(i,1,m){
scanf("%d%d",&e[i].l,&e[i].r);
e[i].id=i; e[i].blo=e[i].l/sz;
}
sort(e+1,e+1+m,cmp);
int l=1,r=0;
rep(i,1,m){
while(e[i].r>r) add(++r);
while(e[i].r<r) del(r--);
while(e[i].l-1<l) add(--l);
while(e[i].l-1>l) del(l++);
ans[e[i].id]=tmp;
}
rep(i,1,m){
printf("%lld\n",ans[i]);
}
return 0;
}