poj 1151 线段树+扫描线(Atlantis矩形面积)
2015-08-25 16:09
169 查看
题意:给定n个矩形 (n<= 100),其顶点坐标是浮点数,可能互相重叠,问这些矩形覆盖到的面积是多大。
思路:线段树+扫描线。用一条直线从左到右扫描,碰到一条矩形竖边的时候,就计算该直线有多长被矩形覆盖,以及被覆盖部分是覆盖了几重。碰到矩形左边,要增加被覆盖的长度,碰到右边, 要减少被覆盖的长度。每碰到一条矩形的纵边,覆盖面积就增加 Len * 该纵边到下一条纵边的距离。Len是此时扫描线被矩形覆盖的长度。
在Y轴进行离散化。n个矩形的2n个横边纵 坐标共构成最多2n-1个区间的边界,对这些区间编号,建立起线段树。
注意灵活运用stl提供的函数。
unique的作用是从输入序列中“删除”所有相邻的重复元素,即去重。
lower_bound()在first和last中的前闭后开区间进行二分查找,返回大于或等于val的第一个元素位置,在本题中即返回查找到的y数组下标。
思路:线段树+扫描线。用一条直线从左到右扫描,碰到一条矩形竖边的时候,就计算该直线有多长被矩形覆盖,以及被覆盖部分是覆盖了几重。碰到矩形左边,要增加被覆盖的长度,碰到右边, 要减少被覆盖的长度。每碰到一条矩形的纵边,覆盖面积就增加 Len * 该纵边到下一条纵边的距离。Len是此时扫描线被矩形覆盖的长度。
在Y轴进行离散化。n个矩形的2n个横边纵 坐标共构成最多2n-1个区间的边界,对这些区间编号,建立起线段树。
注意灵活运用stl提供的函数。
unique的作用是从输入序列中“删除”所有相邻的重复元素,即去重。
lower_bound()在first和last中的前闭后开区间进行二分查找,返回大于或等于val的第一个元素位置,在本题中即返回查找到的y数组下标。
#include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <queue> #include <cstdlib> using namespace std; #define clc(s,t) memset(s,t,sizeof(s)) #define INF 0x3fffffff #define N 100005 struct line{ //表示矩形的竖边 double x,y1,y2; int l; //表示是否为矩形的左边 bool operator<(const line &b) const{ return x<b.x; } }line[N<<1]; struct tree{ int l,r; int num; //覆盖的重数 double len; }t[N<<3]; double y[N<<1]; int ylen; int T = 1,n; int mid(int a,int b){ return (a+b)>>1; } void build(int r,int left,int right){ t[r].l = left; t[r].r = right; t[r].num = t[r].len = 0; if(left == right) return; build(r*2, left, mid(left, right)); build(r*2+1, mid(left, right)+1, right); } void insert(int r,int left,int right){ int mm = mid(t[r].l,t[r].r); if(t[r].l == left && t[r].r == right){ t[r].len = y[right]-y[left-1]; t[r].num++; return; } if(right<=mm) insert(r*2, left, right); else if(left>mm) insert(r*2+1, left, right); else{ insert(r*2, left, mm); insert(r*2+1, mm+1, right); } if(t[r].num == 0) t[r].len = t[r*2].len + t[r*2+1].len; } void del(int r,int left,int right){ int mm = mid(t[r].l, t[r].r); if(t[r].l == left && t[r].r == right){ t[r].num--; if(t[r].num == 0){ if(left == right) t[r].len = 0; else t[r].len = t[r*2].len+t[r*2+1].len; } return; } if(right <= mm) del(r*2,left,right); else if(left > mm) del(r*2+1,left,right); else{ del(r*2,left,mm); del(r*2+1,mm+1,right); } if(t[r].num == 0) t[r].len = t[r*2].len+t[r*2+1].len; } int main(){ while(scanf("%d",&n) && n){ int i,j,y1,y2; double a,b,c,d,res=0; ylen = 0; for(i = 0;i<n;i++){ scanf("%lf %lf %lf %lf",&a,&b,&c,&d); y[ylen++] = b; y[ylen++] = d; line[i*2].x = a; line[i*2].l = 1; line[i*2+1].l = 0; line[i*2+1].x = c; line[i*2].y1 = line[i*2+1].y1 = b; line[i*2].y2 = line[i*2+1].y2 = d; } sort(line,line+2*n); sort(y,y+ylen); ylen = unique(y, y+ylen)-y; build(1,1,ylen-1); //按照区间的个数建树 for(i = 0;i<2*n-1;i++){ y1 = lower_bound(y,y+ylen,line[i].y1)-y; y2 = lower_bound(y,y+ylen,line[i].y2)-y; if(line[i].l) //注意,y[0]~y[1]是区间1 insert(1,y1+1,y2); else del(1,y1+1,y2); res += t[1].len*(line[i+1].x - line[i].x); } printf("Test case #%d\n",T++); printf("Total explored area: %.2lf\n\n",res); } return 0; }
相关文章推荐
- android setCompoundDrawables和setCompoundDrawablesWithIntrinsicBounds区别
- Biorhythms(求模线性方程组--中国剩余定理的完美诠释)
- 最最简单的客户端与服务端的连接
- 示例:Servlet显示当前系统时间(时间格式化)
- android 学习笔记 创建自己的内容提供器
- ReferenceError: $ is not defined $.fn.extend({
- JVM中锁优化简介
- 掌声送给社会人李涛
- 人是怎么被洗脑被控制的?——竞争
- 【iOS学习笔记】面试题归总
- NOPI导出标准格式Excel
- 2015年8月23日总结
- cocos2d-x中Sprite的自动拉伸,适应屏幕
- Java: System.exit() 与安全策略
- 轻松python文本专题-判断对象里面是否是类字符串(推荐使用isinstance(obj,str))
- Oracle生成查询包括对应于所有数据表记录语句中指定的字段名
- NOPI导出标准格式Excel
- 轻松python文本专题-判断对象里面是否是类字符串(推荐使用isinstance(obj,str))
- windows服务器转linux服务器的点滴
- mybatis的动态sql详解(精)