跟踪累积的结果,无需反向操作

时间:2016-06-23 15:27:55

标签: algorithm math data-structures tree

我有一个操作A * A -> A,它是可交换和关联的。这意味着我应用它的顺序并不重要,只要我使用相同的元素。好的。

我必须将它应用于值列表。更确切地说,我必须使用它作为累积列表值的操作。到目前为止,非常好。

然后我有一系列请求将一个元素添加到列表中,或者从列表中删除它。每次插入或删除后,我都必须返回新列表的新累计值。简单,对吧?

问题是我没有反过来;这是无操作' /'如果我只知道b并且告诉我其他操作数必须是a * b,则能够删除a。 (事实上​​,甚至没有身份元素)

所以,我唯一明显的选择是在每次删除时再次累积 - 在线性时间。

我可以做得更好吗?我已经考虑了很多。

答案是,当然我可以......如果我真的想要:我需要实现一个自定义的二叉树,可能是一个红色/黑色的树,以便有最好的最坏情况保证。在value旁边有一个额外的cache,用于存储整个子树的结果。

cache = value * left.cache * right.cache

每次手术后保持这种不变性;那么根缓存是结果。

然而,"实现自定义R / B树,同时保持额外的不变量"我做的事情并不是特别舒服。好吧,我会这样做,但不要发誓它的正确性。另外,日志之前的常量可能很重要。看起来非常笨拙,做一个简单的事情,比如追踪积累。

有没有人看到更好的解决方案?

为了完整性:操作是过滤器的组合。一个过滤器是一对(code, mask),一个值"通过过滤器" if(C位运算符)(value ^ code) & mask == 0;也就是说,如果它对应于mask中设置的位的位等于code中的相应位。因此,联合设置为0(忽略)掩码或代码不同的位,并保持相同的位。

对任何人找到一种方法来利用操作的特定属性以获得比我抽象的一般问题更有效的解决方案的人表示赞赏! ; - )

1 个答案:

答案 0 :(得分:1)

针对您的具体问题,您可以跟踪每个位x:

  1. 掩码中位x设置为1的总次数
  2. 掩码中x位设置为1且代码位x等于0的总次数
  3. 掩码中位x设置为1且代码位x等于1的总次数
  4. 使用这3个计数(对于每个位),可以直接计算所有过滤器的并集。

    复杂度是添加或删除过滤器的O(R)(其中R是掩码中的位数)。