问题: 我偶然发现了Fenwick树(二元索引树),它可以轻松计算累积总和。但是,我只发现了leeves(summands)数量不变的实现(但它们的值可以改变)。 是否有类似广义Fenwick树的东西允许改变背风(加号)的数量,即具有可变大小?
背景 我目前正在编写一些随机模拟代码(用C ++编写):在一个瓮中有球,每个球我有一定的概率p_i被绘制。在绘图事件中,球被绘制(并被移除)并被具有新概率的两个新球替换(并且相应地重新调整所有概率;我已经有效地“重新缩放”,因此不要打扰它)。在某些时候,我开始移除球,使得球的数量围绕恒定值(之前已知)波动。为了有效地进行绘图,我想使用二叉树。标准的Fenwick树完全符合我的要求,只是它不允许更改urn中的球数。
典型数字 从10个球开始,添加球并开始移除球,一旦有大约1000球,那么在球洞中有900到1100个球(即球被添加和移除,使得数量保持在1000左右)。
到目前为止的解决方法 估计所需的球的最大数量(具有一些安全边界,比如1200个球)并使得大小的恒定大小的Fenwick树具有大部分球,最初具有概率0并且被连续更新。
非常感谢你的帮助! 的Matthias
答案 0 :(得分:7)
实际上,正常(不以任何方式概括)Fenwick树允许随时增加叶子的数量。
某些特定实现可能不允许它。但这可以修复。例如,implementation from TopCoder不允许更改叶子数。问题是update
函数修改了从给定索引开始向上的数组元素,当它达到某个限制(MaxVal
)时停止,在我们的例子中,这是预先不知道的。 read
函数迭代向下的数组元素,因此不需要知道当前的数组大小。如果我们在update
和read
之间交换数组迭代代码,则可以修复此问题:现在update
不需要知道MaxVal
,MaxVal
用于read
,我们可以使用最大的更新索引MaxVal
。
int read(int idx){
int sum = 0;
while (idx <= MaxVal){
sum += tree[idx];
idx += (idx & -idx);
}
return sum;
}
void update(int idx ,int val){
while (idx > 0){
tree[idx] += val;
idx -= (idx & -idx);
}
}
注释
read
返回前缀sum)的实现不同,此实现提供后缀sum。如果您需要前缀和,只需从总值中减去read
返回的值。BLSR
等特定指令来做得更好。