题目链接:http://poj.org/problem?id=1151
题目给了n个矩形,每个矩形给了左下角和右上角的坐标,矩形可能会重叠,求的是矩形最后的面积。因为变化范围比较大,我们要用到离散化,重点说一说扫描线的过程:
下面有几个矩形
现在我们假设有一根扫描线,从下往上开始扫描
如图所示,我们可以把整个矩形分成如图各个颜色不同的小矩形,那么这个小矩形的高就是我们扫过的距离,那么剩下了一个变量,那就是矩形的长一直在变化。
我们的线段树就是维护矩形的长,我们给每一个矩形的上下边进行标记,下面的边标记为1,上面的边标记为-1,每遇到一个矩形时,我们知道了标记为1的边,我们就加进来这一条矩形的长,等到扫描到-1时,证明这一条边需要删除。
还要注意这里的线段树指的并不是线段的一个端点,而指的是一个区间,所以我们要计算的时候r+1和r-1
再提一下离散化,离散化就是把一段很大的区间映射到一个小区间内,这样会节省大量空间,要进行离散化,我们先对端点进行排序,然后去重,然后二分找值就可以了
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#define ll long long
using namespace std;
const int maxn = 222 + 10;
struct node
{
double x, y, h;
int flag;
} pos[maxn];
int cnt[maxn << 3];
double sum[maxn << 3],X[maxn];
bool cmp(node a, node b){
return a.h < b.h;
}
void pushup(int cur,int l,int r)
{
if(cnt[cur]) sum[cur] = X[r + 1] - X[l];
else sum[cur] = sum[cur<<1] + sum[cur<< 1 | 1];
}
void update(int l, int r, int val, int cur, int cl,int cr)
{
if(l <= cl && cr <= r)
{
cnt[cur] += val;
pushup(cur, cl, cr);
return ;
}
int mid = cl + cr >> 1;
if(l <= mid)update(l, r, val, cur << 1, cl, mid);
if(r > mid)update(l, r, val, cur << 1 | 1, mid + 1, cr);
pushup(cur, cl, cr);
}
int main()
{
int n;
int t=1;
while(scanf("%d", &n) && n)
{
memset(cnt, 0, sizeof(cnt));
memset(sum, 0, sizeof(sum));
int xx = 0, hh = 0;
for(int i = 1; i <= n; i++)
{
double x1, y1, x2, y2;
scanf("%lf %lf %lf %lf", &x1, &y1, &x2, &y2);
X[++xx] = x1;
X[++xx] = x2;
pos[++hh] = node{x1, x2, y1, 1};
pos[++hh] = node{x1, x2, y2,-1};
}
sort(X + 1, X + 1 + xx);
sort(pos + 1, pos + 1 + hh, cmp);
xx=unique(X + 1, X + xx + 1) - X - 1;
double ans = 0.0;
for(int i = 1; i <= hh; i++)
{
int l=lower_bound(X + 1, X + xx + 1, pos[i].x) - X;
int r=lower_bound(X + 1, X + xx + 1, pos[i].y) - X;
r--;
update(l, r, pos[i].flag, 1, 1, xx - 1);
ans += sum[1] * (pos[i + 1].h - pos[i].h);
}
printf("Test case #%d\nTotal explored area: %.2f\n\n", t++, ans);
}
return 0;
}