📌  相关文章
📜  范围查询以查找具有给定xor的子数组的数量

📅  最后修改于: 2021-04-29 10:40:24             🧑  作者: Mango

给定大小为nq的查询数组arr []和整数k 。每个查询包括一个索引范围[L,R]和任务是计算对索引的数量ij,使得升≤I≤Ĵ≤R(基于1的索引)和所述元件的XOR A [ i],a [i + 1],…,a [j]等于k

例子:

方法:本文讨论如何在每个查询的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))