POJ2528 Mayor's posters

来源:互联网 发布:java和c哪个难 编辑:程序博客网 时间:2024/06/05 23:40

关键词:线段树成段更新,unique函数去重。


POJ上这道题的数据据说很弱,导致很多实际上错误的代码都通过了。最普遍的错误当属离散化错误。

此题首先审题要准确,海报是按单位区域覆盖的,比如一共三张海报,覆盖区间分别是[5,6]、[4,5]、[6,8],答案是2。

基本思路

线段树结点维护两个信息:该区间贴的海报编号;区间是否被覆盖。对于第i张海报,成段更新[li,ri]。处理完所有海报后遍历线段树,碰到被标记为覆盖的结点就把该结点的海报编号放进一个数组,最后统计数组中有几个不同的数,就是答案。


离散化的错误

海报张贴的位置范围很大(1 <= li <= ri <= 10000000),因此必须离散化。所谓离散化就是记下我们需要用到的数字,将他们有序地存在一个数组里,把所有数字从小到大映射到1、2、3……,然后用映射值来建树。对于这道题,首先记录下所有l和r,然后要去掉重复的(去重操作可以用unique函数,O(n)复杂度),到这一步离散化还是有漏洞的,只要比较两组数据即可:

  1. [1,10] [1,4] [6,10]
  2. [1,10] [1,4] [5,10]

它们的离散化结果完全相同,前者是1 4 6 10对应1 2 3 4,后者是1 4 5 10对应1 2 3 4,因此所建的线段树也是完全一样的,最后得出的结果也是一样,但这就不对了,Case1很明显比Case2多露出一张海报,就是在5那个位置。怎么克服这个问题?再添加一些点!去重完成后要挨个比较相邻的数,如果相差大于1就随便添加一个介于它俩的数,这样这个漏洞就补上了。到此为止离散化是正确的了。

刚刚列举的Case1经过正确的离散化应该是:1 4 5 6 10对应1 2 3 4 5.

成段更新操作

  1. 访问到边界区间时标记它被覆盖,更新海报编号,return。
  2. 如果访问的不是边界区间,检查它是否被覆盖。如果是,执行延迟标记下放操作,同时标记它不被覆盖。继续向下递归。



0 0