1. 程式人生 > >XOR (莫隊)

XOR (莫隊)

前綴和 space %d code 次數 前綴 align gif 統計

Time Limit: 2000 ms Memory Limit: 256 MB

Description

  給定一個含有n個整數的序列 a1, a2,..., an.

  定義 f(x,x) = a[x], f(x,y) = a[x] xor a[x + 1] xor ... xor a[y] (y > x).

  本題設有m組詢問,每組詢問含有兩個參數 (l, r) 。對於每組詢問,你需要回答有多少個二元組 (x, y) 滿足 l <= x <= y <= r 並且 f(x, y) = k.

Input

  第一行有3個整數, n, m, k(1 <= n <= 100000, 1 <= m <= 100000, 0 <= k < 10^6).


  第二行共有 n 個非負整數代表整個序列,每個整數均不超過 10^6.
  接下來m行,每行兩個整數 (li, ri), li <= ri

Output

  對於每組詢問,輸出一行表示有多少滿足上述條件的二元組。

Sample Input

Sample Output

5 2 1
1 0 1 1 0
1 2
2 5

2

4

Hint 

  對於10%的數據,$n, m \leq 500$

  對於30%的數據,$n, m \leq 3000$

  對於50%的數據,$n, m \leq 30000$

  對於100%的數據,$n, m \leq 100000$


題解:

  一看範圍就知道是標準$n\sqrt{n}$莫隊啊,是我今天感冒腦抽了想不出這麽簡單的處理嗎......

  

  $[l,r]$異或起來的值剛好等於$k$,維護異或前綴和$a$後,等價於判斷$a_{l-1}\hat{} a_{r}$是否等於$k$。

  那麽用莫隊在這個異或前綴和數組上爬。

  維護莫隊中統計每種值出現次數的數組$cnt$,$cnt_i$表示值為$i$的有多少。

  這樣一來,加入一位$x$對莫隊的影響就是$ans+=cnt_{a[x]\hat{} k}$,刪去一位對莫隊的影響就是$ans-=cnt_{a[x]\hat{} k}$

  當然還要維護$cnt$,加入時先統計影響,再將$cnt_{a[x]}++$;刪除時先從$cnt$裏抹掉:$cnt_{a[x]}--$,再統計影響。

Tips:

  1.原本$[l,r]$的詢問,轉換後最大要考慮到$[l-1,r]$,所以把詢問的左端點都-1.

  2.異或後值可能大於1000000,需多開一倍。


技術分享
 1 #include <cstdio>
 2 #include <cmath>
 3 #include <algorithm>
 4 using namespace std;
 5 typedef long long ll;
 6 const int N=100010;
 7 int n,m,k,di,a[N],cnt[2000010];
 8 ll now,out[N];
 9 struct Query{
10     int l,r,id;
11     friend bool operator < (Query x,Query y){
12         x.l++; y.l++;
13         if(x.l/di!=y.l/di) return x.l/di<y.l/di;
14         return x.r<y.r;
15     }
16 }q[N];
17 void add(int x){
18     now+=cnt[a[x]^k];
19     cnt[a[x]]++;
20 }
21 void dec(int x){
22     cnt[a[x]]--;
23     now-=cnt[a[x]^k];
24 }
25 int main(){
26     scanf("%d%d%d",&n,&m,&k);
27     di=(int)sqrt(n);    
28     for(int i=1,x;i<=n;i++){
29         scanf("%d",&x);
30         a[i]=a[i-1]^x;
31     }
32     for(int i=1;i<=m;i++){
33         scanf("%d%d",&q[i].l,&q[i].r);
34         q[i].l--; q[i].id=i;
35     }
36     sort(q+1,q+1+m);
37     int l=1,r=1;
38     cnt[a[1]]=1;
39     for(int i=1;i<=m;i++){
40         while(r<q[i].r) add(++r);
41         while(r>q[i].r) dec(r--);
42         while(l<q[i].l) dec(l++);
43         while(l>q[i].l) add(--l);
44         out[q[i].id]=now;
45     }
46     for(int i=1;i<=m;i++) printf("%lld\n",out[i]);
47     return 0;
48 }
奇妙代碼

XOR (莫隊)