给定一个树形结构的输入,我们需要回答以下类型的问题:
a)
给定上述树形结构中的一个节点,哪个节点是离该节点最远的节点。
b)
从树形结构中移除特定集合的边。
我已经尝试了很长时间,但我能想到的最好解决方案是:
对于类型a
的查询,调用dfs
函数在O(N)
内返回最远的节点,但我需要做得更好。
对于类型b
的查询,只需更新树形结构[如果存在,则删除边]。
因此,我以上述解决方案大致为O(K*N)
,其中K
是查询数量,N
是节点数。
给定一个树形结构的输入,我们需要回答以下类型的问题:
a)
给定上述树形结构中的一个节点,哪个节点是离该节点最远的节点。
b)
从树形结构中移除特定集合的边。
我已经尝试了很长时间,但我能想到的最好解决方案是:
对于类型a
的查询,调用dfs
函数在O(N)
内返回最远的节点,但我需要做得更好。
对于类型b
的查询,只需更新树形结构[如果存在,则删除边]。
因此,我以上述解决方案大致为O(K*N)
,其中K
是查询数量,N
是节点数。
根据评论(和不必要的负评),似乎需要更详细的解释。首先,对于给定节点,最远的节点通常不是唯一的。例如,想象一条恰好有三个节点的路径。对于中间节点,有两个最远的节点。其中任一个都是解决方案。基于此,想法是在树中找到一个位于两个最远节点之间路径中点的节点(如果这些节点之间的距离是奇数,则可以选择一侧的节点,使得距离仅相差1):如果最远的节点相隔l个节点,则中间节点与它们的路径长度为l/2,或者与一个节点的路径长度为l/2,与另一个节点的路径长度为l/2+1。
使用这个中间节点将树分成两半,随机称为左半部分和右半部分,可以确定任何给定节点的最远节点,如果每个节点知道它是在左半部分还是右半部分:最长路径将通过中间节点进入另一半部分,然后从那里到达距离中间最远的节点。我们将左侧部分中最长路径的长度称为ll,将右侧部分中最长路径的长度称为lr。不失一般性,假设lr < ll(只需交换名称即可)。来自中间节点的各自最远的节点称为nl和nr。请注意,如果有多个子树从中间节点引导到被认为是右侧部分的一部分,只要其中一个最长路径(或者如果唯一,则是最长路径)在左侧部分中即可。唯一剩下的问题是如何在O(n)
时间内找到中间节点:
1
,并给它们一个距离0
。这可以在O(n)
的时间[和空间]内完成。最后一步,找到具有最大距离标签的相邻节点,并将挂在该节点上的树视为左树。在使用BFS标记节点作为左节点时,保持队列中的最后一个节点以找到nl。将所有其他子树视为右树,并使用BFS标记它们作为右节点,同时也找到nr。
我猜,树的预处理可能可以更优雅地完成,可能只需要进行少量的传递,但我确信上述方法是可行的。
O(n)
内完成。不过,我承认,我没有明确说明我所说的中间是什么(指树中位于最远节点之间的位置的节点)。 - Dietmar Kühl