给定大小为n和q的查询数组arr []和整数k 。每个查询包括一个索引范围[L,R]和任务是计算对索引的数量i和j,使得升≤I≤Ĵ≤R(基于1的索引)和所述元件的XOR A [ i],a [i + 1],…,a [j]等于k 。
例子:
Input: arr[] = {1, 1, 1, 0, 2, 3}, q[] = {{2, 6}}, k = 3
Output: 2
{1, 0, 2} and {3} are the required sub-arrays
within the index range [2, 6] (1-based indexing)
Input: arr[] = {1, 1, 1}, q[] = {{1, 3}, {1, 1}, {1, 2}}, k = 1
Output:
4
1
2
方法:本文讨论如何在每个查询的O(n)中查找具有给定xor的子数组,因此,如果q大,则我们的总运行时复杂度将为O(n * q)。
由于我们可以离线查询,因此我们的想法是使用Mo的算法。我们将数组划分为sqrt(n)块,然后根据块索引对查询进行排序,首先用较小的r值断开关系。
我们将保留一个数组xorr [],其中xorr [i]存储数组元素前缀从0到i(基于索引0)的xor。
我们还将保留另一个数组cnt [],其中cnt [y]存储xorr [i] = k的前缀数。
假设我们在索引x处添加一个元素,令xorr [x] ^ k = y,现在,如果cnt [y]大于0,则存在具有相同xor的前缀,因此我们得到具有给定xor k的y子数组。在索引x处结束。
下面是上述方法的实现:
// C++ implementation of the approach
#include
using namespace std;
const long long bsz = 316;
long long res = 0;
// Query structure
struct Query {
long long l, r, q_idx, block_idx;
Query() {}
Query(long long _l, long long _r, long long _q_idx)
{
l = _l, r = _r, q_idx = _q_idx, block_idx = _l / bsz;
}
// We use operator overloading
// to sort the queries
bool operator<(const Query& y) const
{
if (block_idx != y.block_idx)
return block_idx < y.block_idx;
return r < y.r;
}
};
Query queries[1000005];
unordered_map cnt;
long long n, q, k;
long long xorr[1000005];
// Function to add elements while traversing
void add(long long u)
{
long long y = xorr[u] ^ k;
// We find the number of prefixes with value y
// that are contributing to the answer,
// add them to the answer
res = res + cnt[y];
// If we are performing add operation, and suppose
// we are at index u then count of xorr[u]
// will increase by 1 as we are adding
// the answer to the list
cnt[xorr[u]]++;
}
// Function to delete elements while traversing
void del(long long u)
{
// If we are performing delete operation and suppose
// we are at index u then count of xorr[u]
// will decrease by 1 as we are removing
// the answer from the list
cnt[xorr[u]]--;
long long y = xorr[u] ^ k;
// We find the number of prefixes with value y
// that was initially contributing to the answer
// now we do not need them, hence subtract it from answer
res = res - cnt[y];
}
// Here we are performing Mo's algorithm
// if you have no idea of it then go through here:
// https:// www.geeksforgeeks.org/mos-algorithm-query-square-root-decomposition-set-1-introduction/
void Mo()
{
// first we sort the queries with block index, and ties are broken by less r value .
sort(queries + 1, queries + q + 1);
vector ans(q + 1);
long long l = 1, r = 0;
res = 0;
cnt[0] = 1;
// Iterate each query and check whether
// we have to move the left and right pointer
// to left or right
for (long long i = 1; i <= q; ++i) {
// If current right pointer r is less than
// the rightmost index of the present query,
// increment r
while (r < queries[i].r) {
++r;
// While incrementing we are adding new numbers
// to our list. Hence, we modify our answer
// for each r using add() function
add(r);
}
// If current left pointer is greater than the
// left most index of the present query, decrement l
while (l > queries[i].l) {
l--;
// While decrementing l, we are again adding
// new numbers to our list, hence we modify
// our answer using add() function
add(l - 1);
}
// Similarly, if current left pointer is less than
// the left most index of the present query, increment l
while (l < queries[i].l) {
// While incrementing we are deleting elements
// as we are moving right, hence we modify our answer
// using del() function
del(l - 1);
++l;
}
// If current right pointer is greater than the rightmost
// index of the present query, decrement it
while (r > queries[i].r) {
// While decrementing, modify the answer
del(r);
--r;
}
ans[queries[i].q_idx] = res;
}
for (long long i = 1; i <= q; ++i) {
cout << ans[i] << endl;
}
}
// Driver code
int main()
{
q = 3, k = 3;
vector v;
v.push_back(0);
v.push_back(1);
v.push_back(1);
v.push_back(1);
v.push_back(0);
v.push_back(2);
v.push_back(3);
// 1-based indexing
n = v.size() + 1;
xorr[1] = v[1];
for (long long i = 2; i <= n; ++i)
xorr[i] = xorr[i - 1] ^ v[i];
// Queries
queries[1] = Query(1, 6, 1);
queries[2] = Query(2, 4, 2);
queries[3] = Query(2, 6, 3);
Mo();
return 0;
}
3
0
2
时间复杂度: O((n + q)* sqrt(n))