Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/11.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Algorithm 接触段_Algorithm_Sorting_Data Structures_Graph Theory_Overlapping - Fatal编程技术网

Algorithm 接触段

Algorithm 接触段,algorithm,sorting,data-structures,graph-theory,overlapping,Algorithm,Sorting,Data Structures,Graph Theory,Overlapping,谁能给我推荐一下这个算法吗 给定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:我们将在点2和4处绘制两条横穿X轴的线(平行于Y轴)。这两条线将接触所有五段 案例2:即使有一条线在2处穿过X轴,我们也可以接触到所有点 案

谁能给我推荐一下这个算法吗

给定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:我们将在点2和4处绘制两条横穿X轴的线(平行于Y轴)。这两条线将接触所有五段
  • 案例2:即使有一条线在2处穿过X轴,我们也可以接触到所有点
  • 案例3:在这种情况下,触摸不可能超过两个点
限制条件:

1 ≤ N ≤ 10^5
0 ≤ a < b ≤ 10^9
1≤ N≤ 10^5
0≤ a
假设我们有一个有效支持以下操作的数据结构:

  • 添加一个段

  • 删除一段

  • 返回覆盖一个点(即“最佳”点)的最大分段数

  • 如果有这样的结构,我们可以通过以下方式有效地使用初始问题:

  • 让我们创建一个事件数组(一个事件用于每个段的开始,一个事件用于结束)并按x坐标排序

  • 将所有段添加到神奇的数据结构中

  • 迭代所有事件并执行以下操作:当一个段开始时,将一个添加到当前覆盖的段的数量中,并将其从该数据结构中删除。当一个段结束时,从当前覆盖段的数量中减去一个,然后将该段添加到神奇的数据结构中。在每个事件之后,使用当前覆盖的段数(显示与当前事件对应的点覆盖的段数)加上上述数据结构返回的最大值(显示我们如何以最佳方式选择另一个点)的值更新答案

  • 如果此数据结构可以执行
    O(logn)
    中的所有给定操作,那么我们就有了
    O(nlogn)
    解决方案(我们对事件进行排序,并对排序后的数组进行一次遍历,为每个事件对此数据结构进行常量查询)

    那么我们如何实现这个数据结构呢?嗯,分段树在这里很好用。添加线段就是将一个线段添加到特定范围。删除一个线段就是从特定范围内的所有元素中减去一个线段。获取最大值只是段树上的标准最大值操作。因此,我们需要一个支持两种操作的段树:向一个范围添加一个常量,并获取整个树的最大值。它可以在每次查询的
    O(logn)
    时间内完成

    还有一点需要注意:标准段树要求坐标很小。我们可以假设它们永远不会超过
    2*n
    (如果不是这样,我们可以压缩它们)

    一个
    O(N*max(logN,M))
    解决方案,其中M是中等段大小,在公共Lisp中实现:

    其思想是首先从左到右计算每个感兴趣的点上一条直线所接触的线段数(
    openleft-to-right
    lisp代码)。成本:O(NlogN)

    然后,从右到左,再次在每个有趣的点
    p
    ,计算直线的最佳位置,考虑
    p
    的段完全向右(
    在lisp代码上从右到左打开)。成本O(N*max(logN,M))

    然后,只需寻找两个值之和最大的点。成本O(N)

    代码几乎没有经过测试,可能包含bug。此外,我还没有费心处理分段数为零时的边缘情况

  • 问题可以在每个测试用例的O(Nlog(N))时间内解决

  • 请注意,存在两条垂直线的最佳位置,每条垂直线都穿过一些线段端点

  • 压缩段的坐标。更多信息在什么是

  • 构建一组已排序的段端点X

  • a\u i对段进行排序[a\u i,b\u i]

  • 设Q是一个优先级队列,它存储到目前为止处理的段的右端点

  • 设T是建立在x坐标上的最大间隔树。一些有用的阅读材料

  • 对于每个段,进行[a_i,b_i]-范围按1递增查询到T。它允许在[a,b]

  • 迭代x的元素x。对于x>=a_i的每个x处理段(尚未处理)。处理包括将b_i推到Q,并将[a_i,b_i]-范围增量-1查询到T。从Q中移除所有B=T.rmq(x+1,M)返回不覆盖x且覆盖某些固定y>x的最大分段数A+B是答案的候选。

  • 资料来源:

    正好垂直于它们的两条线
    ?那么这两条线将平行于y轴,它们是否需要在整数点处穿过x轴?@PhamTrung,是的,它必须交叉或接触。在整数点处?“还有什么呢?”萨尔瓦说得对,然后呢?我不认为这是件小事。你不能强求,否则复杂性太大big@salva不,接触最多的两个点不一定是最佳点。考虑例如:(1, 3)、(2, 3)、(2, 4)、(5, 6)、(5, 7)、(5, 8)、(5, 9)。您的想法将返回5和6,并触摸4个段,但正确答案之一是1和5。这不是基于线扫描算法吗?@VikasGupta是的,它是。@kraskevich可以告诉您为什么这种方法在某些测试用例中失败:1。做心脏按压2。那么每一里