【Codeforces Round 340 (Div 2)E】【莫隊演算法 真實區間思想】XOR and Favorite Number m組區間詢問 問區間中多少連續段異或值為k
Bob has a favorite numberkandaiof lengthn. Now he asks you to answermqueries. Each query is given by a pairliandriand asks you to count the number of pairs of integersiandj, such thatl ≤ i ≤ j ≤ rand the xor of the numbersai, ai + 1, ..., ajis equal tok.
InputThe first line of the input contains integersn
The second line containsnintegersai(0 ≤ ai ≤ 1 000 000) — Bob's array.
Thenmlines follow. Thei-th line contains integersliandri(1 ≤ li ≤ ri ≤ n) — the parameters of thei-th query.
OutputPrintm
6 2 3 1 2 1 1 0 3 1 6 3 5output
7 0input
5 3 1 1 1 1 1 1 1 5 2 4 1 3output
9 4 4Note
In the first sample the suitable pairs ofiandjfor the first query are: (1,2), (1,4), (1,5), (2,3), (3,6), (5
In the second sample xor equals1for all subarrays of an odd length.
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<string>
#include<ctype.h>
#include<math.h>
#include<set>
#include<map>
#include<vector>
#include<queue>
#include<bitset>
#include<algorithm>
#include<time.h>
using namespace std;
void fre() { freopen("c://test//input.in", "r", stdin); freopen("c://test//output.out", "w", stdout); }
#define MS(x,y) memset(x,y,sizeof(x))
#define MC(x,y) memcpy(x,y,sizeof(x))
#define MP(x,y) make_pair(x,y)
#define ls o<<1
#define rs o<<1|1
typedef long long LL;
typedef unsigned long long UL;
typedef unsigned int UI;
template <class T1, class T2>inline void gmax(T1 &a, T2 b) { if (b>a)a = b; }
template <class T1, class T2>inline void gmin(T1 &a, T2 b) { if (b<a)a = b; }
const int N = 1e5+10, M = 1e5+10, Z = 1e9 + 7, ms63 = 0x3f3f3f3f;
int n, m, k;
struct A
{
int id;
int o;
int l, r;
bool operator < (const A&b)const
{
if (id != b.id)return id < b.id;
return r < b.r;
}
}a[M];
LL ans[M];
int num[(int)1.05e6];
int c[N];
int ins(int p)
{
int tmp = num[c[p] ^ k];
++num[c[p]];
return tmp;
}
int del(int p)
{
--num[c[p]];
int tmp = num[c[p] ^ k];
return tmp;
}
int main()
{
while (~scanf("%d%d%d", &n,&m,&k))
{
int len = sqrt(n);
for (int i = 1; i <= n; ++i)
{
scanf("%d", &c[i]);
c[i] ^= c[i - 1];
}
for (int i = 1; i <= m; ++i)
{
scanf("%d%d", &a[i].l, &a[i].r); --a[i].l;
a[i].id = a[i].l / len;
a[i].o = i;
}
sort(a + 1, a + m + 1);
MS(num, 0);
LL ANS = 0;
int l = a[1].l;
int r = a[1].l-1;
for (int i = 1; i <= m; ++i)
{
while (l > a[i].l)ANS += ins(--l);
while (r < a[i].r)ANS += ins(++r);
while (l < a[i].l)ANS -= del(l++);
while (r > a[i].r)ANS -= del(r--);
ans[a[i].o] = ANS;
}
for (int i = 1; i <= m; ++i)printf("%lld\n", ans[i]);
}
return 0;
}
/*
【trick&&吐槽】
做題的心態千萬要穩住。
1,檢查是否爆int————不要只檢驗答案輸出是lld還是d,所有定義也都要檢查下
2,檢查陣列是否開小。這道題雖然數字的範圍都是1e6,然而,異或之後還是可達2^20-1的。
於是,陣列還是要開到1<<20的
3,這題的異或是對區間
【題意】
給你n(1e5)個數,每個數的權值都在[0,1e6]之間。
有m(1e5)個詢問,
對於每個詢問,給定區間[l,r],問你區間內有多少個連續子段(按照題目定義,顯然非空),
滿足子段的連續異或和恰好為k(k是[0,1e6]範圍的數)
【型別】
莫隊演算法
真是區間思想
【分析】
1,這題詢問眾多,而且詢問都是[l,r]的形式。
我們顯然想到使用莫隊做。
2,涉及到區間連續異或和,我們想到用字首和對映思想。
3,數字範圍最大隻有1e6,於是可以開差不多(其實要1<<20大小),做對映。
這題最關鍵的地方,在於,比如l=5,r=6,我們實際是可以需要用c[6]^c[4]來得到val[5]+val[6]
這裡浪費了很多時間,並且想了很多複雜的方法。
然而,我們如果一旦發現到其真實區間,問題就變得輕而易舉了!
我們發現,對於我們選定的一個區間段,比如l=5,r=5,其實是有兩個位置的,5號位置前,5號位置後,位置的選擇方式並不是r-l-1種,而是r-l種
於是,我們對於所有的查詢區間[l,r],使得l--,使其變成其真實區間[l-1,r]。
然後,我們把所有字首和x都用num[]陣列計數,就可以更新答案了。
如果是區間擴充套件操作,在這個字首和新增進去之間的num[x^k]就是對答案的增貢獻,然後+=num[x]
如果是區間縮減操作,先-=num[x],然後在這個字首和刪除之後的num[x^k]就是對答案的減貢獻。
為什麼區間擴充套件操作先+=num[x^k]再把這個值加進去
而如果是區間縮減操作,則是把這個值刪除,再-=num[x^k]
為什麼這樣子呢?為了防止x^k==x,即這個區間段和自身做匹配的情況發生。
自身與自身做匹配,說明選擇的是空區間段。顯然是不行的。
於是,一個左區間段-1對應到真實區間,一個加減順序解決掉k==0的特殊情況,
用在一起這道題就可以AC啦。
【時間複雜度&&優化】
O(msqrt(n))
【資料】
5 4 0
0 0 0 0 0
1 5
3 3
5 5
2 4
*/