http://www.cnblogs.com/ka200812/archive/2011/11/13/2247064.html
给定一个矩形的左下角坐标和右上角坐标分别为:(x1,y1)、(x2,y2),对这样的一个矩形,我们构造两条线段,一条定位在x1,它在y坐标的区间是[y1,y2],并且给定一个cover域值为1;另一条线段定位在x2,区间一样是[y1,y2],给定它一个cover值为-1。根据这样的方法对每个矩形都构造两个线段,最后将所有的线段根据所定位的x从左到右进行排序。
上图中,红色的字体表示的是该线段的cover值。刚刚开始的时候,线段树上的cover值都为0,但第一根线段(x==0)插入线段树的之后,我们将线段树上的cover加上该线段的cover,那么,此时线段树上被该线段覆盖的位置上的cover的值就为1,下次再插入第二根线段(x==1)此时发现该线段所覆盖的区间内,有一部分线段树的cover为0,另有一部分为1,仔细观察,但插入第二个线段的时候,如果线段树上cover已经为1的那些区间,和现在要插入的第二根线段之间,是不是构成了并面积?还不明白?看下图,绿色部分即为插入第二根线段后得到的并面积
在插入第三条线段时,计算的是1,2,3,4块的面积,在插入第四条线段时,计算5的面积
够清楚了吧!也就是说,我们插入某跟线段的时候,只要看该线段所在区间上的cover是否大于等于1,如果是,那么就可以将并面积值加上(目前线段的x定位 - 上一线段的x定位)*(该区间的大小)
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define lson(i) (idx << 1)
#define rson(i) ((idx << 1) ^ 1)
using namespace std;
const int N = 1010;
double y[N];
struct segment{
double x, y1, y2;
int flag;
segment(){}
segment(const double x, const double y1, const double y2, const int flag){
this->x = x, this->y1 = y1, this->y2 = y2, this->flag = flag;
}
bool operator < (const segment &a) const {
return x < a.x;
}
}line[N];
struct segTree{
int lc, rc, cover;
double up, down, len;
}arr[N * 4];
void pushUp(int idx){
if(arr[idx].cover > 0)
arr[idx].len = arr[idx].up - arr[idx].down;
else
arr[idx].len = arr[lson(idx)].len + arr[rson(idx)].len;
}
void build(int idx, int l, int r){
arr[idx].lc = l, arr[idx].rc = r;
arr[idx].up = y[r], arr[idx].down = y[l];
arr[idx].len = arr[idx].cover = 0;
if(r - l == 1)
return ;
int mid = (l + r) >> 1;
/**
这里和普通的线段树有点不同,不能以左区间[1,mid],右区间[mid+1,r]来建树
如果这样建会漏掉一些线段,比如10,20,30,40这些点来建树,按普通的建法是
[10,20], [30,40],这样[20,30]这跟线段就漏掉了
所以需要左区间[l,mid],右区间[mid,r]这样来建;建出来是[10,20],[20,30],[30,40]
这样就没线段漏掉了.
**/
build(lson(idx), l, mid);
build(rson(idx), mid, r);
}
void update(int idx, int l, int r, int val){
if(arr[idx].lc > r || l > arr[idx].rc)
return ;
if(arr[idx].lc >= l && arr[idx].rc <= r){
arr[idx].cover += val;
pushUp(idx);
return ;
}
update(lson(idx), l, r, val);
update(rson(idx), l, r, val);
pushUp(idx);
}
int main(){
int n, no = 1;
while(cin >> n, n){
int i, idx = 1;
double x1, x2, y1, y2;
for(i = 1;i <= n;i++){
cin >> x1 >> y1 >> x2 >> y2;
line[idx] = segment(x1, y1, y2, 1);
y[idx++] = y1;
line[idx] = segment(x2, y1, y2, -1);
y[idx++] = y2;
}
sort(y + 1, y + idx);
sort(line + 1, line + idx);
/**以y轴建树**/
build(1, 1, idx - 1);
double res = 0;
for(i = 1;i < idx;i++){
res += arr[1].len * (line[i].x - line[i - 1].x);
/**二分出当前扫描线y1,y2的位置**/
int fir = lower_bound(y + 1, y + idx, line[i].y1) - y;
int sec = lower_bound(y + 1, y + idx, line[i].y2) - y;
update(1, fir, sec, line[i].flag);
}
printf("Test case #%d\nTotal explored area: %.2f\n\n", no++, res);
}
return 0;
}