【问题标题】:XOR queries on a given array对给定数组的 XOR 查询
【发布时间】:2021-10-15 23:59:31
【问题描述】:

给定一个包含 n 个整数的数组,索引从 1->n。任务是执行 Q 给定的查询,并在每次查询后打印数组的总和

我们可以执行三种类型的操作:

  • 1 X:将 X 添加到数组中(其索引将为 n+1、n+2、...)
  • 2 Y:从数组中移除索引为 Y 的元素
  • 3 Z:对数组中的每个元素 i,执行 i^Z (i xor Z)

示例:

输入

arr[] = {2, 3, 9, 5, 6, 6}, Q = 5
1 3
3 5
2 2
3 2
2 7

输出: 34 37 31 27 23

解释

1 3 -> arr[] = {2, 3, 9, 5, 6, 6, 3} -> sum = 34

3 5 -> arr[] = {7, 6, 12, 0, 3, 3, 6} -> sum = 37

2 2 -> arr[] = {7, 12, 0, 3, 3, 6} -> sum = 31

3 2 -> arr[] = {5, 14, 2, 1, 1, 4} -> sum = 27

2 7 -> arr[] = {5, 14, 2, 1, 1} -> sum = 23

P/S:我正在尝试解决段树的问题,但我无法使用 XOR 运算符更新树。有没有其他方法可以解决这个问题?我试图在 O(n.logn) 中解决它

【问题讨论】:

  • 2 7(最后一个查询)如何工作?它似乎正在删除数组的第 6 个元素(而不是第 7 个)。或者更确切地说,我想我的问题是:删除操作是缩小数组还是在操作后数组中有一个“洞”?
  • 不确定为什么需要一棵树。提示:尝试分别计算和的每一位。
  • @Maurycyt 这也是我正在努力解决的问题,“2 7”查询删除了索引为 7 的元素(不是第 7 个元素),这是第 6 个元素,因为我们删除了索引为 2 的元素
  • 不,单独考虑每个位只会增加常数,因为(很可能)最多需要考虑 64 位
  • 您不需要在每次执行查询时检查每个数字。您只需执行一次,并存储结果。然后您可以非常快速地更新这些结果。

标签: algorithm xor segment-tree bitwise-xor


【解决方案1】:

假设您的数字不超过一些标准常数,例如 232 或 264,我们可以通过分别计算位来在常数时间内做到这一点。

您需要:

  1. 记住数组中有多少个数字
  2. 记住二进制定位系统中每个位置有多少点亮位。

这是您的示例,扩展为位,最不重要的位在顶部:

2  3  9  5  6  6  3 | sum
-------------------------
0  1  1  1  0  0  1 | 4
1  1  0  0  1  1  1 | 5
0  0  0  1  1  1  0 | 3
0  0  1  0  0  0  0 | 1

现在,这意味着有

  • 4“第一”位点亮
  • 5“第二”位点亮
  • 3“第三”位点亮并
  • 1“第四”位点亮。
  • 号码数量为7
  • 这些数字的总和是34

我们现在用5 对它进行异或,在二进制中是0101,所以现在会有

  • 7 - 4 = 3“第一”位点亮
  • 5“第二”位点亮
  • 7 - 3 = 4“第三”位点亮
  • 1“第四”位点亮

如果我们总结一下,我们会得到 3 * 2^0 + 5 * 2^1 + 4 * 2^2 + 1 * 2^3 = 37(这里的 ^ 我指的是取幂,而不是 xor)。

所以这就是每次异或操作弹出时你所做的。添加和删​​除数字是很容易的部分,因为您检查它们的位并相应地调整数组中点亮的“i-th”位的计数。

【讨论】:

    【解决方案2】:

    感谢Maurycyt 我已经解决了这个问题。以下是我的代码,以防有人需要它

    const int MAX = 1e5 + 5;
    const int MAXBIT = 32;
    int n, q, num, xor_add;
    int arr[MAX], sum[32];
    
    int getSum()
    {
        int res = 0;
        for(int i = 0; i < MAXBIT; i++)
            res += sum[i]*(1<<i);
        return res;
    }
    
    void updateXor(int x){
        xor_add ^= x;
        for(int i = 0; i < MAXBIT; i++)
            if(x & (1<<i))sum[i] = num - sum[i];
    }
    
    void add(int x){
        ++num;
        arr[n++] = x;
        for(int i = 0; i < MAXBIT; i++)
            if(x & (1<<i))sum[i]++;
    }
    
    void remv(int i){
        --num;
        int x = arr[i-1]^xor_add;
        for(int i = 0; i < MAXBIT; i++)
            if(x & (1<<i))sum[i]--;
    }
    
    int main()
    {
        cin >> n >> q;
        num = n;
        for(int i = 0; i < n; i++)cin >> arr[i];
    
        for(int i = 0; i < MAXBIT; i++)
            for(int j = 0; j < n; j++)
                if(arr[j] & (1<<i))sum[i]++;
    
        while(q--){
            int id, x;
            cin >> id >> x;
    
            if(id == 1)add(x);
            else if(id == 2)remv(x);
            else updateXor(x);
    
            cout << getSum() << '\n';
        }
        return 0;
    }
    

    【讨论】:

      猜你喜欢
      • 2019-02-14
      • 2016-03-12
      • 1970-01-01
      • 2015-07-26
      • 2011-12-22
      • 1970-01-01
      • 2019-06-06
      • 1970-01-01
      相关资源
      最近更新 更多