有效地复制/乘法树

Posted

技术标签:

【中文标题】有效地复制/乘法树【英文标题】:Duplicate / multiplicate tree efficiently 【发布时间】:2013-04-17 07:08:10 【问题描述】:

我需要(对于 g++)一个(计算时间)优化的算法树结构来复制/相乘一棵树。

我的树将是一个 k-ary 树,但不一定是填充的。 主要操作是将现有树相乘(最多 k 次)并将树作为子树添加到新节点。然后叶节点级别将被擦除以保持固定级别规则。

有人知道提供此功能的数据结构吗?

乘法示例:假设我们有一棵二叉树

      A
      |
     / \
    /   \
   B     C
   |    / \
   |   /   \
   D   E    F

我们想添加一个新节点/相乘

    R
   / \
  /   \
 ..   ..

所以结果会是这样的

            R
           / \
          /   \
         /     \
        /       \
       /         \
      A           A
      |           |            
     / \         / \        
    /   \       /   \        
   B     C      B     C        
   |    / \     |    / \        
   |   /   \    |   /   \    
   D   E    F   D   E    F    

我试图在 std::vector 上以类似堆的结构组织它,但是乘以树仍然有点慢,因为我必须自己复制每个树级别,而不是一次复制整个树.

【问题讨论】:

@YochaiTimmer std::map 可能是一棵树。但即使特定实现使用树,它也不允许直接操作该树。 【参考方案1】:

当你添加 R 时,给它 2 个指向 A 的指针是微不足道的,而不是从 A 开始复制整个子树。

   R
  / \
  | |
  \ /
   A
   |           
  / \
 /   \
B     C
|    / \
|   /   \
D   E    F

这既快速又易于编码。

现在,如果您稍后想要更新树的一侧,而不是另一侧,那么问题就来了。例如,也许您想将“正确”的 F 更改为 G。此时您可以仅在某些节点上使用 copy-on-write 策略,在这种情况下会导致

      R
     / \
    /   \
   A    A <-- copied, left side points to B
   |   / \        
  / \  *  \  
 /   \     \
B     C     C <-- copied, left side points to E
|    / \   / \
|   /   \  *  \
D   E    F     G

基本上,您只需将路径从更改点 (F/G) 复制到根(最容易实现)或直到共享的最高节点(本例中为 A)。

【讨论】:

【参考方案2】:

也许可以看看 T9 词典的 android 代码。 AFAIR 它看起来很平坦,但基本上他们所做的是构建一个字母树,这样从上到下遍历树就可以生成单词。而且我认为他们使用相对偏移量从一个节点跳转到下一个节点(如链表)。

所以你应该能够一次复制整个树。

我不记得你的确切布局,我认为它没有像我在这里那样做丑陋的填充,但是继续你的例子,它看起来像这样(!):

# your tree

         __________
      ///   _      \      _
     /// /// \      \  /// \
A007021B007000D000000C007014E000000F000000
  \\\_/                   \\\_____/


# copying it, "under" R:
                __________                                __________
     _       ///   _      \      _                     ///   _      \      _
  /// \     /// /// \      \  /// \                   /// /// \      \  /// \
R007049A007021B007000D000000C007014E000000F000000A007021B007000D000000C007014E000000F000000
     \\\ \\\_/                   \\\_____/      /  \\\_/                   \\\_____/
      \\\______________________________________/  

【讨论】:

以上是关于有效地复制/乘法树的主要内容,如果未能解决你的问题,请参考以下文章

加法乘法线段树模板

进阶线段树之乘法操作

P2023 [AHOI2009]维护序列 - 线段树区间乘法加法

线段树—区间乘法

数学计算(线段树乘法)

数学计算(线段树乘法)