扫描线入门&HDU_1542

之前一直在用线段树,但是一遇到扫描线的知识就扔给队友,距离最后一场比赛不到一周的时间了,把之前没学懂的东西补一补。
先来看一个例题

例题:HDU1542

给定平面上的n个矩阵,不同矩阵之间可能有覆盖的部分,问你最后有矩阵覆盖的面积为多少。

输入

包含多组,每组第一行包含一个数字n,接下来是n行,每行包含4个数字,分别为矩阵左下角的x,y坐标,右上角的x,y坐标

输出

对于每组输入,包含一个数字,表示覆盖的面积

输入样例

2
1 1 3 3
2 2 4 4
0

输出样例

7

对于这个题目,我们考虑从左到右扫描这个奇怪的图形,我们将这个图形按照x坐标进行分段处理:
在这里插入图片描述
①x在[1,2]之间,此时y的范围是[1,3],这一部分的面积为2;
在这里插入图片描述
②x在[2,3]之间,此时y的范围是[1,4],这一部分的面积为3;
在这里插入图片描述
③x在[3,4]之间,此时y的范围是[2,4],这一部分的面积为2.
在这里插入图片描述
通过上边的计算步骤,我们不难发现以下几点:
①划分部分的标准是以矩形的左下角和右上角的x坐标,在两个相邻的划分点之间,y的范围是不变的。
②最后总的面积等于每一部分的x坐标的长度乘以对应的y坐标范围
③通过前两点我们不难发现只要能够动态的维护好每一段y的范围就可以算出准确答案。对于y的变化,我们注意到在矩形的左边界,会将这个矩形的y范围与原来的范围进行结合,比如原来的范围为[1,3],现在加入的范围为[2,4],那么最后的范围为[1,4]。同时对于右边界我们发现,它会使得y的范围减去一部分,当然如果有多个矩形包含当前的区间就不会改变或者部分改变。我们利用去重后y的坐标进行线段树的建树,那么可以得到线段树的点代表一段区间,同时我们维护一个lazy数组,lazy[i]表示的是i所代表的区间被多少个矩阵完全覆盖。当我们扫描到矩阵的右边界的时候,我们通过改变lazy数组的大小来维护y的范围。
我们结合样例来理解一下
在这里插入图片描述
首先我们将所有的y值加入Y数组并排序去重,同时将最大的y放到尾部,我们可以得到如下的Y数组:
Y[] = {0,1,2,3,4,4};
我们所建线段树如下
l[1] = 1;r[1] = 4;代表的区间为Y[1]到Y[5]
l[2] = 1;r[2] = 2;代表的区间为Y[1]到Y[3]
l[3] = 3;r[3] = 4;代表的区间为Y[3]到Y[5]
l[4] = 1;r[4] = 1;代表的区间为Y[1]到Y[2]
l[5] = 2;r[5] = 2;代表的区间为Y[2]到Y[3]
l[6] = 3;r[6] = 3;代表的区间为Y[3]到Y[4]
l[7] = 4;r[7] = 4;代表的区间为Y[4]到Y[5]

其中我们tree数组表示当前区间里被覆盖的长度
我们从左到右依次加入边,每条边有三个参数,y的左边界,y的右边界,矩阵的左边界还是右边界(1为左边界,-1为右边界)
初始状态

i tree lazy
1 0 0
2 0 0
3 0 0
4 0 0
5 0 0
6 0 0
7 0 0

加入边(1,3,1)

i tree lazy
1 2 0
2 2 1
3 0 0
4 0 0
5 0 0
6 0 0
7 0 0

其中我们没有下传,是因为我们查询的时候查询的是范围,在点2已经可以获取值,没有必要下传。
加入边(2,4,1)

i tree lazy
1 4 0
2 2 1
3 2 0
4 0 0
5 1 1
6 1 1
7 0 0

加入边(1,3,-1)

i tree lazy
1 3 0
2 1 0
3 2 0
4 0 0
5 1 1
6 1 1
7 0 0

此时,点2的lazy被消除,它所在的区间覆盖长度要去更细的划分中去找,也就是左儿子与右儿子。

最后一条边我们不用去加上,因为加入之后覆盖范围为零

加入边的代码如下:

void push_up(int id,int l,int r)
{
   
    if(lazy[id])//如果当前区间被完全覆盖,那么长度就是左右端点的差值
        tree[id] = Y[r + 1] - Y[l];
    else if(l == r)
        tree[id] = 0;
    else//向左右儿子去找
    {
   
        tree[id] = tree[id << 1] + tree[id << 1 | 1];
    }
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值