对给定数组的 XOR 查询
Posted
技术标签:
【中文标题】对给定数组的 XOR 查询【英文标题】:XOR queries on a given array 【发布时间】: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 位
您不需要在每次执行查询时检查每个数字。您只需执行一次,并存储结果。然后您可以非常快速地更新这些结果。
【参考方案1】:
假设您的数字不超过一些标准常数,例如 232 或 264,我们可以通过分别计算位来在常数时间内做到这一点。
您需要:
-
记住数组中有多少个数字
记住二进制定位系统中每个位置有多少点亮位。
这是您的示例,扩展为位,最不重要的位在顶部:
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;
【讨论】:
以上是关于对给定数组的 XOR 查询的主要内容,如果未能解决你的问题,请参考以下文章