1. 程式人生 > >BZOJ5301: [Cqoi2018]異或序列(莫隊)

BZOJ5301: [Cqoi2018]異或序列(莫隊)

5301: [Cqoi2018]異或序列

Time Limit: 10 Sec  Memory Limit: 512 MB
Submit: 400  Solved: 291
[Submit][Status][Discuss]

Description

已知一個長度為 n 的整數數列 a[1],a[2],…,a[n] ,給定查詢引數 l、r ,問在 [l,r] 區間內,有多少連續子 序列滿足異或和等於 k 。 也就是說,對於所有的 x,y (l≤x≤y≤r),能夠滿足a[x]^a[x+1]^…^a[y]=k的x,y有多少組。

Input

輸入檔案第一行,為3個整數n,m,k。 第二行為空格分開的n個整數,即ai,a2,….an。 接下來m行,每行兩個整數lj,rj,表示一次查詢。 1≤n,m≤105,O≤k,ai≤105,1≤lj≤rj≤n

Output

輸出檔案共m行,對應每個查詢的計算結果。

Sample Input

4 5 1
1 2 3 1
1 4
1 3
2 3
2 4
4 4

Sample Output

4
2
1
2
1

 

沒什麼說的,注意右區間操作時,要考慮左邊的字首。

#include<bits/stdc++.h>
using
namespace std; const int maxn=100010; struct in{int l,r,g,id;}s[maxn]; bool cmp(in w,in v){if(w.g!=v.g) return w.g<v.g; return w.r<v.r;} int sum[maxn],cnt[maxn]; long long ans[maxn]; int main() { int N,M,K,L,R,B,res; scanf("%d%d%d",&N,&M,&K); B=sqrt(N); for(int i=1
;i<=N;i++) scanf("%d",&sum[i]),sum[i]^=sum[i-1]; L=1; R=res=0; for(int i=1;i<=M;i++){ scanf("%d%d",&s[i].l,&s[i].r); s[i].id=i; s[i].g=s[i].l/B; } sort(s+1,s+M+1,cmp); for(int i=1;i<=M;i++) { while(R<s[i].r) cnt[sum[++R]]++,res+=cnt[sum[R]^K]+((sum[R]^K)==sum[L-1]); while(R>s[i].r) res-=cnt[sum[R]^K]+((sum[R]^K)==sum[L-1]),cnt[sum[R--]]--; while(L<s[i].l) res-=cnt[sum[L-1]^K],cnt[sum[L++]]--; while(L>s[i].l) cnt[sum[--L]]++,res+=cnt[sum[L-1]^K]; ans[s[i].id]=res; } for(int i=1;i<=M;i++) printf("%lld\n",ans[i]); return 0; }