我试图理解这段代码。我认为它正在使用段树数据结构的一些变体,但我无法理解此代码中的任何位操作。
实际问题是有N币,我们有1个操作和1个查询
#define LEAVES (131072)
#define MSB_V (0x80000000)
#define MSB_P (31)
int it[2 * LEAVES];
int A, B; //Query range
void flip (int i, int min, int max)
{
if ((min > B) || (max <= A))
{ }
else if ((min >= A) && ((max-1) <= B))
{ it[i] ^= MSB_V; }
else
{
int l = 2 * i;
int r = l + 1;
int mid = (min + max) / 2;
it[l] ^= it[i] & MSB_V;
it[r] ^= it[i] & MSB_V;
it[i] ^= MSB_V;
flip(l, min, mid);
flip(r, mid, max);
it[i] = (it[l] >> MSB_P ? mid - min - (it[l] ^ MSB_V) : it[l]) +
(it[r] >> MSB_P ? max - mid - (it[r] ^ MSB_V) : it[r]);
}
}
int count (int i, int min, int max)
{
int h;
if ((min > B) || (max <= A))
{ h = 0; }
else if ((min >= A) && ((max-1) <= B))
{ h = it[i] >> MSB_P ? max - min - (it[i] ^ MSB_V) : it[i]; }
else
{
int l = 2 * i;
int r = l + 1;
int mid = (min + max) / 2;
it[l] ^= it[i] & MSB_V;
it[r] ^= it[i] & MSB_V;
it[i] ^= MSB_V;
it[i] = (it[l] >> MSB_P ? mid - min - (it[l] ^ MSB_V) : it[l]) +
(it[r] >> MSB_P ? max - mid - (it[r] ^ MSB_V) : it[r]);
h = count(l, min, mid) + count(r, mid, max);
}
return h;
}
有人可以给我一些提示,说明所有这些位操作背后的逻辑是什么
答案 0 :(得分:4)
it
表示完整的二叉树;节点1是根节点,节点k的子节点是2k和2k + 1。
完整二叉树的叶子是硬币。内部节点是面向某种方式(低位31位)和“翻转”标记(位于符号位)的硬币数。如果翻转市场清晰,则低31位计算节点子树中的抬头硬币数量,而如果设置了翻转位,则计算尾部硬币。
此处find
和count
使用的参数约定是i
是要计数或翻转的节点,min
是该节点表示的最低索引,并且max
是最高指数。 find
和count
中的前两个测试检查翻转/计数范围(由A
和B
定义)是否与节点i
不相交或包含的范围。
您在flip
中看到的是:
flip
。一旦我们完成了这个,这里的不变量就毁了;通过将两个孩子中的单挑硬币数相加来修复它。您在count
中看到的是: