POJ 1151 Atlantis(线段树+扫描线)
2015-12-06 16:31
387 查看
Description
求n个矩形的面积并
Input
多组用例,每组用例第一行为一整数n表示矩形个数,之后n行每行四个浮点数x1,y1,x2,y2分别表示该矩形左下端点和右上端点的坐标,以n=0结束输入
Output
对于每组用例,输出这n个矩形的面积并
Sample Input
2
10 10 20 20
15 15 25 25.5
0
Sample Output
Test case #1
Total explored area: 180.00
Solution
首先将每个矩形用左右两边表示并标记每个线段是左边的边还是右边的边,然后对这些线段按x坐标升序排序,用一根线从左往右扫描这些线段,那么相邻两根扫描线之间围成的矩形面积之和即为面积并,那么我们只需要知道每个扫描线上被线段覆盖的长度,将其乘以相邻两根扫描线之间的距离即为扫描线扫过的面积,因此我们对y轴建一棵线段树(对所有线段的纵坐标离散化后建树),那么每条线段就可以用线段树中的一个区间来表示,每次扫到左边的边就在线段树中覆盖这条边对应的区间,扫到右边的边就在线段树中取消对这条边的覆盖,每扫过一根线段就维护一下扫描线被覆盖的长度即可
Code
求n个矩形的面积并
Input
多组用例,每组用例第一行为一整数n表示矩形个数,之后n行每行四个浮点数x1,y1,x2,y2分别表示该矩形左下端点和右上端点的坐标,以n=0结束输入
Output
对于每组用例,输出这n个矩形的面积并
Sample Input
2
10 10 20 20
15 15 25 25.5
0
Sample Output
Test case #1
Total explored area: 180.00
Solution
首先将每个矩形用左右两边表示并标记每个线段是左边的边还是右边的边,然后对这些线段按x坐标升序排序,用一根线从左往右扫描这些线段,那么相邻两根扫描线之间围成的矩形面积之和即为面积并,那么我们只需要知道每个扫描线上被线段覆盖的长度,将其乘以相邻两根扫描线之间的距离即为扫描线扫过的面积,因此我们对y轴建一棵线段树(对所有线段的纵坐标离散化后建树),那么每条线段就可以用线段树中的一个区间来表示,每次扫到左边的边就在线段树中覆盖这条边对应的区间,扫到右边的边就在线段树中取消对这条边的覆盖,每扫过一根线段就维护一下扫描线被覆盖的长度即可
Code
#include<cstdio> #include<iostream> #include<algorithm> #include<cstring> #include<cmath> using namespace std; #define maxn 222 #define eps 1e-8 struct Tree { int left,right,num;//num记录这个区间被覆盖的次数 double len;//len记录这个区间被覆盖的长度 }T[4*maxn]; struct Line { double x,y1,y2; bool flag; }line[maxn]; int n,cnt,res; double y[maxn],ans,len; bool equal(double x,double y) { return fabs(x-y)<eps; } void add(double x,double y1,double y2,double yy,int flag) { line[cnt].x=x;line[cnt].y1=y1;line[cnt].y2=y2;line[cnt].flag=flag;y[cnt++]=yy; } bool cmp(Line l1,Line l2) { if(l1.x!=l2.x) return l1.x<l2.x; return l1.flag>l2.flag; } void build(int l,int r,int t) { T[t].left=l; T[t].right=r; T[t].num=0; T[t].len=0; if(l+1==r)return ; int mid=(l+r)>>1; build(l,mid,2*t); build(mid,r,2*t+1); } void update_len(int t) { if(T[t].num) T[t].len=y[T[t].right]-y[T[t].left]; else if(T[t].left+1==T[t].right) T[t].len=0; else T[t].len=T[2*t].len+T[2*t+1].len; } void update(double l,double r,int t,int x) { if(equal(y[T[t].left],l)&&equal(y[T[t].right],r)) T[t].num+=x; if(T[t].left+1<T[t].right) { int mid=(T[t].left+T[t].right)>>1; if(r<=y[mid]+eps) update(l,r,2*t,x); else if(l>=y[mid]-eps) update(l,r,2*t+1,x); else { update(l,y[mid],2*t,x); update(y[mid],r,2*t+1,x); } } update_len(t); } int main() { int t=1; while(~scanf("%d",&n),n) { cnt=0;ans=0;len=0; double x1,x2,y1,y2; while(n--) { scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2); //将每个矩形用左右两边表示 add(x1,y1,y2,y1,1); add(x2,y1,y2,y2,0); } sort(line,line+cnt,cmp);//对得到的线段按x升序排序 //对y轴建树 sort(y,y+cnt); res=unique(y,y+cnt)-y; build(0,res-1,1); for(int i=0;i<cnt;i++) { if(line[i].flag) update(line[i].y1,line[i].y2,1,1);//扫到左边的边就在线段树中覆盖这部分 else update(line[i].y1,line[i].y2,1,-1);//扫到右边的边就在线段树中取消这部分的覆盖 if(i) ans+=len*(line[i].x-line[i-1].x);//累加每次扫描线扫过的面积 len=T[1].len;//维护扫描线上被覆盖的长度 } printf("Test case #%d\n",t++); printf("Total explored area: %.2lf\n\n",ans); } return 0; }
相关文章推荐
- 【Html】三种CSS样式的优先级
- 图片保存
- FUZoj 过河I 2188 (bfs多条件判断) 好题
- 理解iOS中的MVC设计模式
- nginx 1.9.7安装使用
- 守护线程和非守护线程
- opencv配置相关
- PAT乙级 福尔摩斯的约会 (20)
- windowsPE系统的制作
- Android获取状态栏、标题栏、ActionBar以及屏幕的高度
- 读《暗时间》的很多摘抄与很少感悟
- 使用Gson解析常见json字符串
- C 标准库 strcmp 函数的实现
- 子数组的最大乘积
- C语言练习作业(六)
- Android中使用Dialog风格弹出框的Activity
- 剑指offer学习笔记1
- iOS8中添加的extensions总结(四)——Action扩展
- 数据注解特性之ConcurrencyCheck特性【Code-First系列】
- 初始react