会遇到这种题:给你很多矩形,如果一个区域被多次覆盖,只计算一次,问总面积.

一直说是线段树,但是不知道是扫描线,写篇博客记录一下.

扫描线是这么个意思

肯定需要离散化了,可以选择离散化x轴或者y轴的点,然后就分割成了几个区间,x1到x2,x2到x3,x3到x4,我们以xi代表以它为起点,以下一个离散化的点为终点的线段.

然后我们有四个高度,y1,y2,y3,y4,可以知道,面积等于(y2-y1)*(x3-x1)+.........这样面积实际上就可控了.

那么具体操作怎么办捏,以离散化x轴为栗子,我们在输入的时候可以找到一个上边和下边,我们把下边标记为1,上边标记-1,

排序之后,y1,2,3,4顺次排序,

现在开始处理:

这是第一次的情况,y1是下底边,[x1,x3)被标记为1,然后乘以这段的高.以HDU1542的样例为假设,

样例:

2
10 10 20 20
15 15 25 25.5
0

则黄色部分就是(20-10)*(15-10) = 50;

第二次的情况:

现在我们扫描了y2,此时我们的对x2,x3进行了扫描,现在横轴长度变为[x1,x4),为什么捏,因为之前的图一,黄色部分覆盖了[x1,x3),现在[x2,x3)被扫描两次,[x1,x2)被扫描一次,所以,此时的面积是蓝色部分加上和蓝色部分平行的黄色部分,是(20-15(高))*(25-10(长)) = 75.

第三次扫描,是对y3进行扫描,之前都是下边界,现在遇到上边界-1的情况了.

下面的箭头就是这个上边界扫描完产生的变化,然后面积就是黄色部分加起来,再之后是y4的扫描,-1之后等于0,可扫可不扫.

//Atlantis HDU - 1542
#include<bits/stdc++.h>
using namespace std;
const int maxn = 505;
int lazy[maxn<<2];
int add[maxn<<2];
double x[maxn<<2],sum[maxn<<2];
struct EDGE
{int ss;//上下边double l,r,h;//左右,高度EDGE(double _x1=0,double _x2=0,double _y=0,int _up_or_down=0){l = _x1;r = _x2;h = _y;ss = _up_or_down;}bool operator<(const EDGE & a){return h<a.h;}
} dian[maxn];
void pushUP(int rt,int l,int r)
{if(add[rt])//如果有标记,则长度为标记的长度sum[rt] = x[r+1]-x[l];else if(l == r)//相等则为长度0sum[rt] = 0;else sum[rt] = sum[rt<<1]+sum[rt<<1|1];//等于左边+右边的sum
}
void update(int rt,int L,int R,int val,int l,int r)//更新[l,r]区间
{int mid;if(L<=l && R >= r){add[rt] += val;pushUP(rt,l,r);return;}mid = (l+r)>>1;if(L<=mid)update(rt<<1,L,R,val,l,mid);if(R>mid)update(rt<<1|1,L,R,val,mid+1,r);pushUP(rt,l,r);
}
int main()
{
//    freopen("in.txt","r",stdin);ios::sync_with_stdio(false);cin.tie(0),cout.tie(0);int n;int kase = 1;double x1,y1,x2,y2,ans;while(cin>>n && n){ans = 0;int top = 0,l,r;printf("Test case #%d\n",kase++);printf("Total explored area: ");for(int i=0; i<n; i++){cin>>x1>>y1>>x2>>y2;x[top] = x1;dian[top++] = EDGE(x1,x2,y1,1);//下边界标记为1x[top] = x2;dian[top++] = EDGE(x1,x2,y2,-1);//上边界标记为-1}sort(x,x+top);sort(dian,dian+top);int k = 1;for(int i=1; i<top; i++){if(x[i] != x[i-1])x[k++] = x[i];//序列离散化变成[0,k);}memset(add,0,sizeof(add));memset(sum,0,sizeof(sum));for(int i=0; i<top-1; i++){l = lower_bound(x,x+k,dian[i].l)-x;//下边界r = lower_bound(x,x+k,dian[i].r)-x-1;//上边界,因为每个点代表的是以当前点为起点的下一段,所以要-1update(1,l,r,dian[i].ss,0,k-1);//更新[0,k-1]区间ans += (sum[1]*(dian[i+1].h-dian[i].h));}printf("%.2f\n\n",ans);}return 0;
}

然后开始解析代码职能,sum需要统计的是add标记过的长度,add是标记现在当前段被几个下边界+1,我们的边需要按照高度从小到大排序,ss表示+1和-1,sum[1]就是被标记的有效长度,然后由于区间是[)的,所以r lower_bound之后需要-1,

关于去重:据说可去可不去,意义:把x轴离散化之后变成有序的,相当于打个映射.二分的时候直接是严格单调递增的,其他的没有影响.

变形题:

Rectangles Gym - 101982F

当时打死都不会,还以为是二维线段树,其实好像没这东西,全是自己瞎猜的.

现在要处理的问题比较狗了一点,还是那么扫描,但是负负得正,正正得负,记得一个运算,^运算,所以我们现在+val应该改成^1;

//【扫描线】Gym - 101982 - F - Rectangles
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn = 1e5+5;
int lazy[maxn<<3];
int add[maxn<<3];
int x[maxn<<2],sum[maxn<<3];
struct EDGE
{int ss;//上下边int l,r,h;//左右,高度EDGE(int _x1=0,int _x2=0,int _y=0){l = _x1;r = _x2;h = _y;}bool operator<(const EDGE & a){return h<a.h;}
} e[maxn<<2];
void cal(int rt,int l,int r)//长度里面减去之前有标记的
{sum[rt] = (x[r]-x[l])-sum[rt];
}
void pushUP(int rt)//向上更新正常求和
{sum[rt] = sum[rt<<1]+sum[rt<<1|1];
}
void pushDown(int rt,int l,int r)//向下更新
{if(!add[rt])return;add[rt<<1] ^= 1;add[rt<<1|1] ^= 1;int mid = (l+r)>>1;cal(rt<<1,l,mid);//计算sumcal(rt<<1|1,mid,r);add[rt] = 0;
}
void update(int rt,int L,int R,int l,int r)//更新[L,R]区间
{int mid;if(L<=l && R >= r)//如果rt包含的区间完全被覆盖{add[rt] ^= 1;cal(rt,l,r);return;}pushDown(rt,l,r);//向下更新一次懒惰标记mid = (l+r)>>1;if(L<mid)update(rt<<1,L,R,l,mid);if(R>mid)update(rt<<1|1,L,R,mid,r);pushUP(rt);
}
int main()
{int n;scanf("%d",&n);int x1,x2,y1,y2,all=0;for(int i=1; i<=n; i++){scanf("%d%d%d%d",&x1,&y1,&x2,&y2);e[2*i-1].l=min(x1,x2);//l严格小于re[2*i-1].r=max(x1,x2);e[2*i-1].h=min(y1,y2);e[2*i].l=min(x1,x2);e[2*i].r=max(x1,x2);e[2*i].h=max(y1,y2);x[2*i-1]=x1,x[2*i]=x2;}sort(x+1,x+1+n*2);all=unique(x+1,x+1+n*2)-x-1;for(int i=1; i<=2*n; i++)//处理出来l和r在离散化之后的x轴上的区间e[i].l=lower_bound(x+1,x+1+all,e[i].l)-x,e[i].r=lower_bound(x+1,x+1+all,e[i].r)-x;sort(e+1,e+1+2*n);LL ans=0;for(int i=1; i<2*n; i++){update(1,e[i].l,e[i].r,1,all);//更新这条线段ans+=(LL)sum[1]*(e[i+1].h-e[i].h);}printf("%lld\n",ans);
}

扫描线算法讲解+例题相关推荐

  1. 【线段树】【模板】讲解 + 例题1 HDU - 1754 I Hate It (点修改分数)+ 例题二 POJ - 3468 A Simple Problem with Integers(区间加值)

    [线段树][模板]讲解 + 例题1 HDU - 1754 I Hate It (点修改分数)+ 例题二 POJ - 3468 A Simple Problem with Integers(区间加值) ...

  2. 原创 子网划分的讲解 例题加思路

    转载于:https://blog.51cto.com/13039592/1959175

  3. kruskal 重构树(讲解 + 例题)

    kruskal重构树 如何建树 模仿kruskalkruskalkruskal,先将所有边排序. 依次遍历每一条边,如果这条边的两个节点(u,vu, vu,v)不在同一个连通块里面, 则新建一个nod ...

  4. 已知分布函数求概率密度例题_高中数学必修一函数知识点总结

    同学们,今天开始讲解函数章节学习,函数这章极其重要,因为函数是高中数学重要的枢纽章节,高中数学除了立体几何和概率统计和函数没有关系之外,所有章节多多少少和函数有关系,所以函数学不好高中数学很难突破10 ...

  5. 【数据结构期末例题】

    前言 本文是博主自己在准备学校数据结构考试时的总结,各个知识点都贴有对应的详细讲解文章以供大家参考:当然文中还有许许多多的截图,这些是博主对主要内容的摘取,对于那些基础较好的同学可以直接看截图,减少跳 ...

  6. 作为一名程序员,数学到底对你有多重要?

    最近在知乎上看到一个贴子,看完后我沉默了..... 沉思后想想,其实每个行业都会分等级,程序员也不例外!说好听一点的叫工程师,普通一点的叫程序员,差一点的叫码农,更差的还会叫码畜,码奴.(哎..... ...

  7. 初中数学四十二个几何模型_模型 | 一文搞定初中数学9大重要几何模型(优选)...

    文章来源:王通博初中数学,ID:wtbmaths近日小初QQ群更新的部分内容如下2020年中考数学真题分类汇编版本1(58讲Word)2020年中考数学真题分类汇编版本2(21讲Word)2020年全 ...

  8. 利用计算机进行有理数的运算教学反思,《有理数加减乘除混合运算》教学反思...

    <有理数加减乘除混合运算>教学反思 作为一名到岗不久的老师,课堂教学是我们的工作之一,通过教学反思可以快速积累我们的教学经验,那么你有了解过教学反思吗?下面是小编收集整理的<有理数加 ...

  9. 推理计算过程_初中物理电学计算题第六讲:极值问题推理和限制条件

    初中物理电学计算题第六讲:极值问题推理和限制条件 前面已经讲过:初中物理电学计算题第三讲:串联电路电流电阻极值推理实例,本讲是这一问题的进一步深入讨论. 题型分析 极值问题是电学计算题中一类较难的题目 ...

最新文章

  1. Nlpir大数据知识图谱的落地指南
  2. Making Sense of Cryptoeconomics
  3. java按钮陷下去_付费?广告?捐款?如何让开源软件活下去?
  4. python生成泊松分布随机数_Python Numpy random.poisson() 泊松分布
  5. 编程语言python入门-编程语言入门(以python为例)
  6. css3图片 变黑白 变模糊 调整饱和度等
  7. java json字符串转成 Map或List
  8. 简单async数据分批处理
  9. 计算机及编程语言历史概述
  10. word解除限制编辑(亲测有效)
  11. Android真正的静默安装
  12. BDBR和BD-PSNR
  13. 伴风网易博客linux,网易博客链接
  14. 学习pathon工具安装
  15. ai水墨晕染效果_AI可能是一位优秀的西方画家,但它在中国水墨画中表现良好吗?...
  16. Go语言核心之美 2.4-布尔值
  17. 老司机的奇怪noip模拟T1-guanyu
  18. HTML5期末大作业:饮食食品主题设计——绿色简洁生鲜超市网站设计(5页) HTML+CSS+JavaScript web前端大二实训大作业
  19. OmniPlan 项目管理入门
  20. iOS - 定制多样式二维码

热门文章

  1. 金融壹账通将在港交所“双重”上市,2021财年营收达41亿元
  2. 一个难倒三线城市所有开发人员,主要在数据库构架,您认为是我的方案行的通吗,还是他们没修炼?
  3. 超详细windows安装并配置mongo数据库
  4. 刮刮乐,前端代码html+js实现,直接运行
  5. shader实现的“地表最强护盾”,没有之一
  6. 51NOD--1414 冰雕--思维
  7. AdScopes收益分析 | 百万日活APP,一天广告收入有多少?一文教你如何计算
  8. oaf java_OAF 多语言的实现
  9. 单片机MCU软硬件联调基本方法
  10. 黑猩猩优化算法python代码(详细注释)