查找给定范围内的最小元素大于给定数字

时间:2013-09-05 15:26:50

标签: performance algorithm data-structures segment-tree range-query

我们在2D平面上给出N(N <= 10 6 )点和整数D(N <= 10 6 ),我们想要找到两个点p1,p2(p1右侧的p2),使p1.yp2.y之间的差异至少为D,p2.x - p1.x最小化。

x轴和y轴的范围为0..10 6

这是来自USACO过去比赛的problem

这是我尝试解决它:
MAXY = N个点中的最大y轴 假设我们知道p1,那么我们很容易找到p2;通过获取y轴在p1.y+D到MAXY范围内或在0到p1.y-D范围内的所有点,并取x轴最小的点大于p.x 。这将是p2的最佳选择。

但是由于我们不知道p1,我们必须尝试p1的所有点,因此找到p2的最佳选择应该有效地完成。

我使用了一个分段树。树中的每个节点都将按照x轴的排序顺序存储相应范围内的所有点。在查询时,如果一个节点落在查询范围内,那么我们在数组上二进制搜索p1.x并返回大于它的最小元素。

对于p1的每个选择,我们使用范围0,p1.y-D和p1.y + D,MAXY两次查询树,并取出返回的两个点中的最佳值。

树的构建可以在O(NlogN)时间内完成。 每个查询都需要O(logN * logN)时间,我们进行N次查询,因此所花费的总时间为(Nlogn * logn),可能不会在2秒的时间限制内运行。 (10 6 * 20 * 20)。 此外,所占用的内存为O(NlogN),约为80 mb(100000 * 20 * 4 kb),超出限制为64 mb。

我们如何更快地进行查询并使用更小的空间?

2 个答案:

答案 0 :(得分:5)

可以更轻松地完成。

假设您有两个数组副本:一个按Y轴排序,另一个按X轴排序。现在,您将遍历Y排序的数组,并且对于每个点(让它命名为cur),您应该在X排序的数组中二进制搜索适当的点(具有最小的p2.x - p1.x)。如果二进制搜索会找到相同的点或Y坐标小于cur + D的点,你应该从X排序的数组中删除该点(我们再也不需要在X排序的数组中的那个点,因为我们只增加Y坐标)并再次运行二进制搜索。答案将是二进制搜索结果中最小的。

由于我们需要快速计时,我们应该快速从阵列中擦除点。它可以通过使用二叉树来完成 - 它可以在O(logN)时间内擦除任何节点,并且可以在O(logN)时间内进行二进制搜索。当您从树中删除每个节点一次并且需要O(logN + logN)时间时 - 总时间将为O(N * logN)。预处理时间也是O(N * logN)。所采用的存储器也将是O(N)。

顺便说一句,你的解决方案也是合适的,因为实际N是10 ^ 5而不是10 ^ 6。这允许您的解决方案将时间保持在2秒以下,并使用少于20MB的内存。

答案 1 :(得分:1)

排序&amp; amp;扫描。

按x排序,因为您希望通过x找到最小差异。它需要O(N logN)时间。

从x的头部维护两个索引i和j。

首先越快,找到| P [i] .y - P [j] .y |的位置&GT; d

和X = | P [i] .x - P [j] .x |是您的第一个选择。

然后通过向前移动索引来更新X.尝试P [i + 1],从P [i + 2]扫描为P [j]并增加直到| P [i] .x - P [j] .x | &gt; = X.如果有可用的新X,请将其设置为X。

这可能首先会做很多比较。但是,既然你更新你的X,不知何故会使你的比较范围缩小。