任何人都可以为我推荐算法。
在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
答案 0 :(得分:3)
假设我们有一个有效支持以下操作的数据结构:
添加细分。
删除细分。
返回覆盖一个点的最大段数(即“最佳”点)。
如果有这样的结构,我们可以通过以下方式有效地使用初始问题:
让我们创建一个事件数组(每个段开始一个事件,结束一个事件),然后按x坐标排序。
将所有细分添加到神奇的数据结构中。
迭代所有事件并执行以下操作:当段开始时,将一个添加到当前覆盖的段的数量,并从该数据结构中删除它。当一个段结束时,从当前覆盖的段的数量中减去一个,并将该段添加到神奇的数据结构中。在每个事件之后,使用当前覆盖的段的数量值(它显示与当前事件对应的点覆盖的段数)加上上述数据结构返回的最大值来更新答案(它显示了我们如何可以用最好的方式选择另一个点。)
如果这个数据结构可以执行O(log n)
中的所有给定操作,那么我们有一个O(n log n)
解决方案(我们对事件进行排序并对排序后的数组进行一次传递,对此进行一定数量的查询每个事件的数据结构。)
那么我们如何实现这种数据结构呢?那么,段树在这里工作正常。添加一个段是将一个添加到特定范围。删除段会从特定范围内的所有元素中减去一个。获取最大值只是段树上的标准最大操作。所以我们需要一个支持两个操作的段树:向一个范围添加一个常量并为整个树获得最大值。它可以在每个查询O(log n)
时间内完成。
还有一点需要注意:标准的分段树要求坐标很小。我们可以假设它们永远不会超过2 * n
(如果不是这样,我们可以压缩它们)。
答案 1 :(得分:1)
O(N*max(logN, M))
解决方案,其中M是中等段大小,在Common Lisp中实现:touching-segments.lisp。
我们的想法是首先在每个有趣的点从左到右计算一条线所触及的线段数(在lisp代码上为open-left-to-right
)。费用:O(NlogN)
然后,从右到左,它再次在每个有趣的点P
计算一条线的最佳位置,将{strong>完全向右的段P
({关于lisp代码的{1}}。成本O(N * max(logN,M))
然后,只需要找到两个值之和的顶点。成本O(N)。
代码几乎没有经过测试,可能包含错误。此外,我还没有打算处理边缘情况,因为当段数为零时。
答案 2 :(得分:1)
每个测试用例的 O(Nlog(N))时间可以解决问题。
观察到两条垂直线的最佳位置,每条垂直线都经过一些段端点
压缩段的坐标。更多信息,请参阅什么是coordinate compression?
构建一组有序的细分端点 X
按 a_i
设Q为优先级队列,存储到目前为止处理的段的右端点
设T是在x坐标上构建的最大间隔树。一些有用的阅读What are some sources (books, etc.) from where I can learn about Interval, Segment, Range trees?
对于每个细分,将 [a_i,b_i] - 范围按1的增量查询添加到T 。它允许在[a,b]
中找到涵盖某些x的最大段数迭代X的元素x。对于每个x进程段(尚未处理) x&gt; = a_i。处理包括将 b_i推送到Q 并使 [a_i,b_i] - 范围增量 - ( - 1)查询到T 。从Q中删除所有元素&lt; x,A = Q.size等于覆盖x的段数。 B = T.rmq(x + 1,M)返回未覆盖x的最大段数并覆盖某些固定的y&gt; X。 A + B是答案的候选人。