📜  在给定范围内出现偶数次的数字的XOR

📅  最后修改于: 2021-04-17 08:23:18             🧑  作者: Mango

给定一个数字数组,大小为N和Q。每个查询或范围可以由L(LeftIndex)和R(RightIndex)表示。查找在给定范围内出现偶数次的数字的XOR和。

先决条件:查询给定范围内不同数字的数量。 |用于范围查询的细分树

例子 :

Input : arr[] = { 1, 2, 1, 3, 3, 2, 3 }
        Q = 5
        L = 3,  R = 6
        L = 3,  R = 4
        L = 0,  R = 2
        L = 0,  R = 6
        L = 0,  R = 4
Output : 0
         3
         1
         3
         2

以上示例说明:
在查询1中,没有数字出现偶数次。
因此,XOR和为0。
在查询2中,{3}出现偶数次。 XOR和为3。
在查询3中,{1}出现偶数次。 XOR和为1。
在查询4中,{1,2}出现偶数次。 XOR-sum是1 xor 2 = 3。
在查询5中,{1,3}出现偶数次。 XOR-sum是1 xor 3 = 2。

段树或二进制索引树可用于有效解决此问题。

方法 :
首先,很容易注意到查询的答案是查询范围内所有元素的XOR和与查询范围中不同元素的XOR和求和(因为将元素与自身结果的XOR求和空值)。使用前缀XOR-sums查找查询范围内所有数字的XOR-sum。
要查找范围内不同元素的XOR和:给定范围子数组中不同元素的数量。
现在,回到我们的主要问题,只需将BIT [i] = 1更改为BIT [i] = arr i并计算XOR-sum而不是sum。

以下是在CPP中使用二进制索引树的实现

// CPP Program to Find the XOR-sum
// of elements that appeared even
// number of times within a range
#include 
using namespace std;
  
/* structure to store queries
   L --> Left Bound of Query
   R --> Right Bound of Query
   idx --> Query Number */
struct que {
    int L, R, idx;
};
  
// cmp function to sort queries 
// according to R
bool cmp(que a, que b)
{
    if (a.R != b.R)
        return a.R < b.R;
    else
        return a.L < b.L;
}
  
/*  N  --> Number of elements present in
    input array. BIT[0..N] --> Array that 
    represents Binary Indexed Tree*/
  
// Returns XOR-sum of arr[0..index]. This
// function assumes that the array is
// preprocessed and partial sums of array 
// elements are stored in BIT[].
int getSum(int BIT[], int index)
{
    // Iniialize result
    int xorSum = 0;
  
    // index in BITree[] is 1 more than
    // the index in arr[]
    index = index + 1;
  
    // Traverse ancestors of BIT[index]
    while (index > 0) 
    {
        // Take XOR of current element 
        // of BIT to xorSum
        xorSum ^= BIT[index];
  
        // Move index to parent node
        // in getSum View
        index -= index & (-index);
    }
    return xorSum;
}
  
// Updates a node in Binary Index Tree
// (BIT) at given index in BIT.  The
// given value 'val' is xored to BIT[i] 
// and all of its ancestors in tree.
void updateBIT(int BIT[], int N, 
               int index, int val)
{
    // index in BITree[] is 1 more than 
    // the index in arr[]
    index = index + 1;
  
    // Traverse all ancestors and 
    // take xor with 'val'
    while (index <= N) 
    {
        // Take xor with 'val' to 
        // current node of BIT
        BIT[index] ^= val;
  
        // Update index to that of 
        // parent in update View
        index += index & (-index);
    }
}
  
// Constructs and returns a Binary Indexed
// Tree for given array of size N.
int* constructBITree(int arr[], int N)
{
    // Create and initialize BITree[] as 0
    int* BIT = new int[N + 1];
      
    for (int i = 1; i <= N; i++)
        BIT[i] = 0;
  
    return BIT;
}
  
// Function to answer the Queries
void answeringQueries(int arr[], int N,
        que queries[], int Q, int BIT[])
{
    // Creating an array to calculate
    // prefix XOR sums
    int* prefixXOR = new int[N + 1];
  
    // map for coordinate compression
    // as numbers can be very large but we
    // have limited space
    map mp;
  
    for (int i = 0; i < N; i++) {
          
        // If A[i] has not appeared yet
        if (!mp[arr[i]])
            mp[arr[i]] = i;
  
        // calculate prefixXOR sums
        if (i == 0)
            prefixXOR[i] = arr[i];
        else
            prefixXOR[i] = 
                prefixXOR[i - 1] ^ arr[i];
    }
  
    // Creating an array to store the
    // last occurrence of arr[i]
    int lastOcc[1000001];
    memset(lastOcc, -1, sizeof(lastOcc));
  
    // sort the queries according to comparator
    sort(queries, queries + Q, cmp);
  
    // answer for each query
    int res[Q];
  
    // Query Counter
    int j = 0;
      
    for (int i = 0; i < Q; i++) 
    {
        while (j <= queries[i].R) 
        {
            // If last visit is not -1 update
            // arr[j] to set null by taking
            // xor with itself at the idx 
            // equal lastOcc[mp[arr[j]]]
            if (lastOcc[mp[arr[j]]] != -1)
                updateBIT(BIT, N, 
                      lastOcc[mp[arr[j]]], arr[j]);
  
            // Setting lastOcc[mp[arr[j]]] as j and
            // updating the BIT array accordingly
            updateBIT(BIT, N, j, arr[j]);
            lastOcc[mp[arr[j]]] = j;
            j++;
        }
  
        // get the XOR-sum of all elements within
        // range using precomputed prefix XORsums
        int allXOR = prefixXOR[queries[i].R] ^ 
                     prefixXOR[queries[i].L - 1];
  
        // get the XOR-sum of distinct elements
        // within range using BIT query function
        int distinctXOR = getSum(BIT, queries[i].R) ^ 
                          getSum(BIT, queries[i].L - 1);
  
        // store the final answer at the numbered query
        res[queries[i].idx] = allXOR ^ distinctXOR;
    }
  
    // Output the result
    for (int i = 0; i < Q; i++)
        cout << res[i] << endl;
}
  
// Driver program to test above functions
int main()
{
    int arr[] = { 1, 2, 1, 3, 3, 2, 3 };
    int N = sizeof(arr) / sizeof(arr[0]);
  
    int* BIT = constructBITree(arr, N);
  
    // structure of array for queries
    que queries[5];
  
    // Intializing values (L, R, idx) to queries
    queries[0].L = 3; 
    queries[0].R = 6, queries[0].idx = 0;
    queries[1].L = 3; 
    queries[1].R = 4, queries[1].idx = 1;
    queries[2].L = 0; 
    queries[2].R = 2, queries[2].idx = 2;
    queries[3].L = 0; 
    queries[3].R = 6, queries[3].idx = 3;
    queries[4].L = 0; 
    queries[4].R = 4, queries[4].idx = 4;
  
    int Q = sizeof(queries) / sizeof(queries[0]);
  
    // answer Queries
    answeringQueries(arr, N, queries, Q, BIT);
  
    return 0;
}
输出:
0
3
1
3
2

时间复杂度: O(Q * Log(N)),其中N是数组的大小,Q是查询的总数。