题意:求给出的n个矩形的面积并
题目链接:http://poj.org/problem?id=1151
思路:
终于接触扫描线了,nice~~~
1.由于坐标是浮点数,离散化(如果数据范围很大或者浮点数,离散化 ^_^)
2.如何扫着过去,求出面积呢?
看下面的图:
(直接借用的~~)
每个矩形直接转换为两条线,这两条线分别是上边和下边,对应的y1,此时对应的横坐标区间[x1,x2] 和 y2对应的横坐标区间也是[x1,x2],
同时那些线也就是y从哪里来的呢,是那些矩形的y坐标排序,这样子扫过去,只要确定了每两条线之间的宽度,那么相邻两条线的高度差*宽度也就是一个小矩形的面积了,所有的加起来也就是并的和了,
从y扫过去的时候,首先将一条边插入线段树,然后得到当前当前扫描线所在位置的覆盖到的边的总长,
第一次插入A1B1,扫描线覆盖的边长就是A1B1,再用它直接乘高度就是第一个小矩形的面积;
第二次插入的时候,扫描覆盖的边长就是A2B2,同理可得到第二个矩形的面积;
第三次插入的时候,由于已经到达第一个矩形的上边,无法进行计算,(如何判断是不是上边呢,就需要一个标记,-1)那么此时覆盖的边长也就是A3B3了,同理可得到第二个矩形的面积;
三者相加就是总面积了
注意的一点:
插入的时候也得注意,不是根据坐标计算出其离散值就当做区间直接插入,而是要将右坐标的离散值减1,这个线段树中,每个点代表一个区间
#include <iostream> #include <stdio.h> #include <stdio.h> #include <string.h> #include <algorithm> using namespace std; #define maxn 1000 #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 struct LINE{ double y,x_left,x_right; int flag; LINE(){} LINE(double _y,double _x_left,double _x_right,int _f):y(_y),x_left(_x_left),x_right(_x_right),flag(_f){} }line[maxn<<2]; int cover[maxn<<2]; double sum[maxn<<2]; double X[maxn<<2]; double x1,y1,x2,y2; int n,t; bool cmp(double a,double b){ if(a < b) return true; return false; } bool cmp1(LINE a,LINE b){ if(a.y < b.y) return true; return false; } int erfen(double res){ int left = 0 , right = t - 1, mid; while(left <= right){ mid = (left + right )/2; if(X[mid] == res) return mid + 1; else if(X[mid] < res) left = mid + 1; else right = mid - 1; } return -1; } void PushUp(int l,int r,int rt){ if(cover[rt]) sum[rt] = X[r] - X[l - 1]; else if(l == r) sum[rt] = 0; else sum[rt] =sum[rt<<1]+ sum[rt<<1|1]; } void update(int L,int R,int c,int l,int r,int rt){ if(L <= l && r <= R){ cover[rt] += c; PushUp(l,r,rt); return ; } int m = (l + r)/2; if(L <= m) update(L,R,c,lson); if(m < R) update(L,R,c,rson); PushUp(l,r,rt); } int main() { int ncase = 1; while(~scanf("%d",&n) && n){ t = 0; for(int i=0;i<n;i++){ scanf("%lf %lf %lf %lf",&x1,&y1,&x2,&y2); line[t] = LINE(y1,x1,x2,1); X[t++] = x1; line[t] = LINE(y2,x1,x2,-1); X[t++] = x2; } sort(X,X+t,cmp); sort(line,line+t,cmp1); memset(sum,0,sizeof(sum)); memset(cover,0,sizeof(cover)); double ans = 0; for(int i = 0 ;i < t - 1;i++){ int l = erfen(line[i].x_left) ; int r = erfen(line[i].x_right) - 1 ; update(l , r ,line[i].flag , 1 , t , 1); ans += (line[i + 1].y - line[i].y) * sum[1]; } printf("Test case #%d\n",ncase++); printf("Total explored area: %.2lf\n\n",ans); } return 0; }