线段树辅助——扫描线法计算矩形周长并(轮廓线)
有两种方法,不过常用的第二种,两种都说一下。
第一种:
把矩形分成横线和竖线去处理,可知是完全相同的操作,我们来讲下怎么算出横线部分,竖线部分就是照搬即可。
将横线保存在一个表中,按横线所处的竖直位置排序(升序),另外每条横线带一个标记值,原矩形的下线为1,上线为-1(对应过去就是插入线段和删除线段)
从低到高扫描横线,没扫到一条横线就能计算出一部分横线值。计算方法是算出现在总区间的被覆盖的长度,然后求出与上一次的总区间的覆盖长度的差(即相减求绝对值),因为每次添加了一条线段,如果没有没有使总区间覆盖长度发生变化,说明这条线段其实在多边形的内部,被覆盖掉了,不能计算,只要能引起总区间长度发生变化的,说明该线段不被覆盖不被包含,要计算
而竖线部分的做法是一样的,把竖线保存在一个表中,按水平位置排序(升序),每条横线带一个标记值,原矩形的左线为1,右线为-1,然后同样地操作
第二种:
上面的方法显得有点“笨”,相同的工作做了两次,可不可以只扫描一次矩形就求出答案,是可以的,但是我们要改进一下线段树节点记录的信息
每个线段树的节点要记录几个信息
1.l,r,该节点代表的线段的左右端点坐标
2.lp,rp,是一个标记量,只有0,1,表示这个节点左右两个端点没有被覆盖,有为1,无为0
3.cnt,表示这个区间被重复覆盖了几次
4.len,这个区间被覆盖的长度
5.num,这个区间被多少条线段覆盖
好像区间[0,10],被[1,2],[4,5]覆盖,那么num=2
好像区间[0,10],被[1,3][4,5]覆盖,那么num=1,因为他们刚好连在一起了
好像区间[0,10],被[1,5][2,6]覆盖,那么num=1,因为还是连起来的一段
前面的工作是相同的,把横线保存在一个表中,按竖直位置排序,然后从下往上扫描所有横线,在这个方法中,每次扫描一条横线,都能计算出两不部分值,一部分是横线的,一部分是竖线的
而计算横线部分的方法和第一种方法是一样的,即求出【现在这次总区间被覆盖的长度和上一次总区间被覆盖的长度的差的绝对值】,另外怎么算竖线部分呢?首先我们要知道添加了这条横线后会有多少条竖线,答案是2*num,所以为什么要记录num呢,因为总区间被num条线段覆盖,那么必定有2*num的端点,这些端点其实就是连着竖线,那么这些竖线的长度是多少呢?
就是【下一条横线的高度-现在这条横线的高度】,只要把这个高度乘上2*num即可