有人可以为此建议我的算法吗。
您将获得x轴上N个分段的起点和终点。垂直于它们的两条线(即使在它们的边缘)也可以触摸其中的多少?
样本输入:
3
5
2 3
1 3
1 5
3 4
4 5
5
1 2
1 3
2 3
1 4
1 5
3
1 2
3 4
5 6
样本输出:
Case 1: 5
Case 2: 5
Case 3: 2
说明:
约束:
1 ≤ N ≤ 10^5
0 ≤ a < b ≤ 10^9
假设我们有一个有效地支持以下操作的数据结构:
添加细分。
删除段。
返回覆盖一个点(即“最佳”点)的最大段数。
如果具有这样的结构,我们可以通过以下方式有效地使用初始问题:
让我们创建一个事件数组(每个段的开始一个事件,结束一个事件)并按x坐标排序。
将所有段添加到神奇的数据结构中。
遍历所有事件并执行以下操作:当段开始时,将一个添加到当前覆盖的段数并将其从该数据结构中删除。当一个段结束时,从当前覆盖的段数中减去一个,然后将此段添加到神奇的数据结构中。在每个事件之后,用当前覆盖的段数(显示与当前事件相对应的点覆盖多少段)的值和上述数据结构返回的最大值更新答案(显示我们如何可以以最佳方式选择另一点。
如果此数据结构可以执行O(log n)
中的所有给定操作,则我们有O(n log n)
解决方案(我们对事件进行排序,并在排序后的数组上进行一次遍历,对每个事件对该数据结构进行恒定数量的查询)。
那么我们如何实现这种数据结构?好吧,段树在这里工作正常。添加细分是将细分添加到特定范围。删除段就是从特定范围内的所有元素中减去一个。获得最大值只是段树上的标准最大值操作。因此,我们需要一个支持两种操作的分段树:将一个常数添加到范围中,并获得整个树的最大值。可以在每个查询的O(log n)
时间内完成。
另外一个注意:标准分段树要求坐标较小。我们可以假设它们永远不会超过2 * n
(如果不是这种情况,我们可以压缩它们)。
O(N*max(logN, M))
解决方案,其中M是中等段大小,在Common Lisp中实现:touching-segments.lisp。
想法是首先在每个有趣的点从左到右计算那里的一条线(lisp代码上的open-left-to-right
)将触及的段数。费用:O(NlogN)
然后,从右到左,它再次在每个有趣的点P
处考虑P
的段[[完全在右边(在Lisp代码上为open-right-to-left
),计算一条线的最佳位置。费用O(N * max(logN,M))
该代码未经测试,可能包含错误。另外,当段数为零时,我也不想处理边缘情况。
O(Nlog(N))时间内解决问题。
X
[[a_i,b_i]让Q为优先级队列,该队列存储到目前为止已处理的段的正确端点
让T是建立在x坐标上的最大间隔树。在What are some sources (books, etc.) from where I can learn about Interval, Segment, Range trees?中有一些有用的读物
对于每个段,使
对T的1增量查询。它允许找到覆盖[a,b]中的一些x
b_i to Q
推入并生成[a_i,b_i ]-范围以(-1)递增查询到T。从Q中删除所有元素