线段树 + 扫描线加深具体解释

在线段树中的扫描线主要是解决矩形面积以及周长问题,比方下图

让你求解全部矩形覆盖的面积和,或者是周长和,假设用平常的方法,很之麻烦。并且效率也不高。这里就会用到线段树的扫描线

扫描线应对方案:

因为题目提供的矩形比較多。坐标也非常大。所以坐标须要离散化,能够依照题目要求或者自己的喜好,离散横坐标或者纵坐标都能够,这里讲的都是离散横坐标,不离散纵坐标

假设有一条扫描线,从下往上(从上往下)扫描过整个多边形叠加的区域。假设是竖直方向上扫描,则是离散化横坐标,假设是水平方向右扫描,

在进行扫描前。要保存好全部矩形的上边和下边。而且依照它们所处的高度进行排序,另外我们给上边赋值为-1。给上边赋值为1。接着我们用一个结构体来保存全部矩形的上边和下边,当中还有两条边不用管,由于他们已经包含在了高度中。高度差便能得到边的长度。

struct seg {

double l,r,h;//l代表着一条边左边端点的横坐标,r表示一条边右边端点的横坐标。h表示这条边所在的高度

int s;//表示他的值。即我们在前面讲的给边赋值1或者-1

seg() {}

seg(double l,double r,double h,int s):l(l),r(r),h(h),s(s) {}

bool operator < (const seg & object) const {//依照高度排序

return h < object.h;

}

}

然后将扫描线从下往上扫描。每遇到一条上边或者下边就停下来,将这条线段增加到总区间上,下边赋值是1,扫描到下边的话相当于往总区间插入一条线段。上边为-1。扫描到上边相当于在总区间删除一条线段(也能够理解为当插入1的时候我们的扫描线在一个矩形中,当插入-1的时候证明我们的扫描线离开了一个矩形的区域,如此能够知道,区间不会出现负数的情况,由于永远都是下边1 >= 上边-1。他们相加是永远大于等于零的)

然后用下一条边的高度减去当前这条边的高度,乘上总区间被覆盖的长度,就能得到终于的面积

到此。希望大家能够做一做这道题目,理解一下大概http://blog.csdn.net/qq_18661257/article/details/47622677

这道题目说明一下,pushup(rt, l, r)的作用以及当中推断的来由。

  1. void pushup(int rt,int l,int r) {
  2. if (Col[rt]) Sum[rt] = X[r+1] - X[l];//利用[ , ),这个区间性质。左闭右开
  3. else if (l == r) Sum[rt] = 0;
  4. else Sum[rt] = Sum[rt<<1] + Sum[rt<<1|1];
  5. }

假设当前的位置为叶子节点,Col[rt] == 1话证明被全然覆盖了,进行赋值(这里涉及到了离散化,建议读者能够学习离散化的知识),假设为Col[rt] == 0,这个叶子节点一定为0

假设当前位置不是叶子节点那么我们就要小心一点了。Col[rt] == 1话证明被全然覆盖了,假设Col[rt] == 0话。我们能说他没有被覆盖吗,不能,仅仅能说没有被全然覆盖,为什么呢,由于他的子节点可能被全然覆盖了,可是父亲节点没有覆盖,那么怎么全然的不漏的得到这个区间被全然覆盖的区间大小呢,能够直接通过子节点覆盖的值

Sum[rt] = Sum[rt << 1] + Sum[rt << 1|1]得到rt这个位置总覆盖区间

好,假设我如今要求被覆盖两次以及以上的区间的面积怎么做,图形例如以下:

那么我们就要多添加一个数组用来记录覆盖了两次或者两次以上的区间大小。

Sum[rt]表示覆盖了一次的区间

Sum2[rt]表示覆盖了两次的区间

最開始跟上面的没有什么差别

假设Col[rt] >= 2的话。非常明显这个区间一定都被覆盖了至少是两次

假设Col[rt] == 1的话,这里大家能够思考一下,直接从Sum2[rt] = Sum[rt << 1] + Sum[rt << 1|1]

这里为什么是从子节点传上来呢,假设Col[rt] == 1的话。证明此时这个位置已经被覆盖了一次,假设子节点也被覆盖了一次那不就是子节点被覆盖了两次吗,如此直接传给父亲节点,表示这个区间被覆盖了两次的答案

如此,假设Col[rt] == 0的话,证明这个地方没有被覆盖一次。那么我们仅仅有从子节点将覆盖了两次的结果传来了。

Sum2[rt] = Sum2[rt << 1] + Sum2[rt << 1|1];

  1. void pushup(int rt,int l,int r) {
  2. if(Col[rt]) Sum[rt] = X[r + 1] - X[l];
  3. else if(l == r) Sum[rt] = 0;
  4. else Sum[rt] = Sum[rt << 1] + Sum[rt << 1|1];
  5. if(Col[rt] >= 2) Sum2[rt] = X[r + 1] - X[l];
  6. else if(l == r) Sum2[rt] = 0;
  7. else if(Col[rt] == 1) Sum2[rt] = Sum[rt << 1] + Sum[rt << 1|1];
  8. else if(Col[rt] == 0) Sum2[rt] = Sum2[rt << 1] + Sum2[rt << 1|1];
  9. }

提供模板出处:http://blog.csdn.net/qq_18661257/article/details/47658101

时间: 2024-08-01 21:36:53

线段树 + 扫描线加深具体解释的相关文章

hdu 1255 覆盖的面积(线段树&amp;扫描线&amp;重复面积)

覆盖的面积 Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 3375    Accepted Submission(s): 1645 Problem Description 给定平面上若干矩形,求出被这些矩形覆盖过至少两次的区域的面积. Input 输入数据的第一行是一个正整数T(1<=T<=100),代表测试数据的数量.每个测试数

【BZOJ】1382: [Baltic2001]Mars Maps (线段树+扫描线)

1382: [Baltic2001]Mars Maps Time Limit: 5 Sec  Memory Limit: 64 MB Description 给出N个矩形,N<=10000.其坐标不超过10^9.求其面积并 Input 先给出一个数字N,代表有N个矩形. 接下来N行,每行四个数,代表矩形的坐标. Output 输出面积并 Sample Input 2 10 10 20 20 15 15 25 30 Sample Output 225 本以为是傻逼题,没想到不容易啊- 线段树+扫描

BZOJ 4059 Cerc2012 Non-boring sequences 线段树+扫描线

题目大意:定义一个序列为[不无聊的]当且仅当这个序列的任意一个区间都存在一个数只出现过一次,给定一个序列,要求判断这个序列是否是[不无聊的] 定义lasti表示第i个元素上一次出现的位置(第一次出现则为0),nexti表示第i个元素下一次出现的位置(最后一次出现则为n+1),那么这个元素能成为某个区间仅出现一次的数,当且仅当这个区间的左端点在[lasti+1,i]之间,右端点在[i,nexti?1]之间 我们可以将区间的左右端点放在二维平面上,那么一个元素产生的贡献是一个矩形,我们要确定的是所有

HDU 4419 Colourful Rectangle --离散化+线段树扫描线

题意: 有三种颜色的矩形n个,不同颜色的矩形重叠会生成不同的颜色,总共有R,G,B,RG,RB,GB,RGB 7种颜色,问7种颜色每种颜色的面积. 解法: 很容易想到线段树扫描线求矩形面积并,但是如何维护每种颜色的长度着实让我伤透了脑筋.后来看了一位朋友的题解,才幡然醒悟. 开始想到了用二进制表示颜色,R用001表示,G用010表示,B用100表示.那么就可以用十进制1~7表示7种不同颜色了. 维护 cov[rt][1~3] 表示此区间内3种原色各有多少个, Len[rt][i]表示每种颜色的长

sgu316Kalevich Strikes Back(线段树+扫描线)

做法:总体想法是求出一个矩形的面积以及它所包含的矩形,然后用自己的面积减掉所包含的.主要问题是怎样求解它所包含的矩形. 因为是没有相交点的,可以利用扫描线的方法去做,类似染色,当前段如果是x色,也就是第x个矩形,那么再把他染成y颜色时,说明x包含y,而当扫到y的上边时,这一段又恢复到x色.标记一下被包含的矩形,记录所包含的矩形. 因为会有恢复染色操作,up需要时时更新,左儿子和右儿子一样颜色时就可以合并为一段. 1 ; 2 } 3 void down(int w) 4 { 5 if(s[w]!=

hdu1255 覆盖的面积 线段树-扫描线

矩形面积并 线段树-扫描线裸题 1 #include<stdio.h> 2 #include<string.h> 3 #include<algorithm> 4 #include<math.h> 5 using namespace std; 6 const int maxm=2e3+5; 7 const double eps=1e-5; 8 9 struct seg{ 10 double x,y1,y2; 11 int c; 12 bool operator

线段树+扫描线 HDOJ 5091 Beam Cannon

题目传送门 1 /* 2 题意:给出若干个点的坐标,用一个矩形去覆盖,问最多能覆盖几个点 3 线段树+扫描线:思路是先建一棵以[y, y + h]的树,左右儿子[x, x + w] 4 以这棵树为范围,从左到右扫描,更新点数,x的+1, x+w的-1(超过矩形范围) 5 ans = 每次更新时所覆盖点数的最大值 6 */ 7 #include <cstdio> 8 #include <algorithm> 9 #include <iostream> 10 #includ

POJ 3277 City Horizon(线段树+扫描线+离散化)

题目地址:POJ 3277 水题..稍微处理一下然后用求面积并的方法求即可. 代码如下: #include <iostream> #include <cstdio> #include <string> #include <cstring> #include <stdlib.h> #include <math.h> #include <ctype.h> #include <queue> #include <

[POI 2001+2014acm上海邀请赛]Gold Mine/Beam Cannon 线段树+扫描线

Description Byteman, one of the most deserving employee of The Goldmine of Byteland, is about to retire by the end of the year. The Goldmine management would like to reward him in acknowledgment of his conscientious work. As a reward Byteman may rece