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