给定一个输入树,我们需要回答该类型的查询,a)
给出了上述树的一个节点,该节点是距离该节点最长的节点。b)
从树中删除一组特定的边。
我已经尝试了很长时间,但是我能想到的最好的解决方案是,
对于a
类型的查询,请调用dfs
函数,该函数将返回O(N)
中最远的节点,但我需要做得更好。
对于b
类型的查询,只需更新树[删除边缘(如果存在)]。
因此,我上面的解决方案大致是O(K*N)
,其中K
是查询数,而N
是节点数。
最佳答案
由于您的树是一棵普通的树,也就是说,它没有平衡甚至没 Root过的概念,因此对于一次性查询,最好的方法是O(n)
。但是,我认为您可以一次花费O(n)
时间来设置树,然后让随后的每个查询花费固定的时间。
想法是找到树的“中间”,将树分成大致相等大小的树,称其为任意部分,例如左右。然后,用它们所在的部分标记它们各自部分中的所有节点,并存储距离中间最远的左侧和右侧节点。当您查询某个节点时,只需查看该节点的标签并在另一侧报告已存储的节点即可。
考虑到评论(和毫无根据的批评),解决方案似乎需要更多的解释。首先,给定节点最远的节点通常不是唯一的。想象一下一个路径,它恰好具有三个节点。中间节点有两个最远的节点。解决方案之一。基于此,我们的想法是在树中找到一个节点,该节点位于树中两个相距最远的节点之间的路径的中间(这些节点之间的距离为奇数,可以选择任一侧的节点这样距离相差仅1):如果相距最远的节点相距l个节点,则中间节点的路径长度均为l/2到它们两个,或者路径长度为l/2到一个且l/2 + 1到另一个。
使用此中间节点将树分成两半,随机分为左右两半,这样就可以确定每个给定节点的相距最远的节点(如果每个节点都知道它在左半部分还是右半部分中):最长的路径将穿过中间节点进入另一半,然后再从那里到达最远离中间节点的节点。让我们将左侧部分ll中最长路径的长度称为右侧部分lr中最长路径的长度。在不失一般性的前提下,将lr
当您要声明与节点n距离最远的节点时,需要考虑以下三种情况:
剩下的唯一问题是如何在O(n)
时间中找到中间节点:1
标记它们,并给它们指定0
的距离。这可以在O(n)
时间[和空格]中完成。
作为最后一遍,找到具有最大距离标签的相邻节点,并将悬在该节点上的树视为左树。在使用BFS将节点标记为左节点时,请跟踪队列中的最后一个节点以查找nl。将所有其他子树视为正确的树,并用BFS标记它们,作为正确的节点,也找到nr。
我猜想,可以更优雅地完成树的预处理,也可以使用少量遍,但是我确信上述方法确实有效。
关于c++ - 节点与树中另一个节点的距离最大,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19888999/