题意:
给你n个矩形的左下角坐标和右上角坐标,求矩形相交的面积。
思路:
先学习一下矩形面积并。矩形面积并
就是把这一堆矩形切分成不同的矩形条来处理,每个矩形条的高度就是相邻矩形条的高度之差,而长度就是当前扫描线经过的这些矩形的长度和(用线段树来统计),长度*高度就是这一小块的面积,这样一条一条处理,最终一大块不规则的图形就处理完了。
参考:https://blog.youkuaiyun.com/WhereIsHeroFrom/article/details/78969718
注意:这里的线段树和之前的线段树稍微有点区别,就是叶子结点的区间端点不再相等,而是相差1,即l+1 == r。因为一个点对于计算面积来说是没有意义的。
例如:一个[1, 4]的区间,我们建树:
#include <cstdio>
#include <cstring>
#include <algorithm>
#define lson l, mid, root<<1
#define rson mid, r, root<<1|1 // 注意!!!,这里的区间分配有些不一样
using namespace std;
const int INF = 0x3f3f3f3f;
typedef long long LL;
const int maxn = 200+5;
double X[maxn];
// 矩形的水平边
struct Edge{
double l, r, h; // 横坐标区间, 纵坐标
int pos; // 是矩形的上边还是下边
Edge(){}
Edge(double l, double r, double h, int p):l(l),r(r),h(h),pos(p){}
bool operator < (const Edge& rhs)const{
return h < rhs.h;
}
}edges[maxn];
// 线段树节点
struct Node{
int cover; // 区间被完全覆盖的次数
double len; // 区间内被覆盖的实际长度
}Tree[maxn<<2];
void Stree_build(int l, int r, int root){
Tree[root].cover = 0; Tree[root].len = 0.0;
if(l+1 == r) return;
int mid = (l+r) >> 1;
Stree_build(lson);
Stree_build(rson);
}
void push_up(int l, int r, int root){
if(Tree[root].cover > 0) Tree[root].len = X[r] - X[l];
else if(l+1 == r) Tree[root].len = 0;
else Tree[root].len = Tree[root<<1].len + Tree[root<<1|1].len;
}
void update(int la, int rb, int l, int r, int root, int val){
if(la > r||rb < l) return;
if(la <= l&&rb >= r){
Tree[root].cover+= val;
push_up(l, r, root);
return;
}
if(l+1 == r) return;
int mid = (l+r) >> 1;
if(la <= mid) update(la, rb, lson, val);
if(rb > mid) update(la, rb, rson, val);
push_up(l, r, root);
}
int main()
{
freopen("in.txt","r",stdin);
double x1, y1, x2, y2;
int kase = 1, n;
while(scanf("%d",&n) == 1&&n){
int tot = 0;
for(int i = 0; i < n; ++i){
scanf("%lf%lf%lf%lf", &x1,&y1,&x2,&y2);
edges[++tot] = Edge(x1, x2, y1, 1);
X[tot] = x1;
edges[++tot] = Edge(x1, x2, y2, -1);
X[tot] = x2;
}
sort(edges+1, edges+tot+1); // 所有边按照高度排序
sort(X+1, X+tot+1);
// printf("tot = %d\n", tot);
// for(int i = 1; i <= tot; ++i) printf("%.2lf ", X[i]);
// 横坐标去重——离散化
int k = 1;
for(int i = 2; i <= tot; ++i){
if(X[i] != X[i-1]) X[++k] = X[i];
}
Stree_build(1, k, 1);
double ans = 0;
for(int i = 1; i < tot; ++i){
int l = lower_bound(X+1, X+k+1, edges[i].l) - X;
int r = lower_bound(X+1, X+k+1, edges[i].r) - X;
//printf("l = %d, r = %d\n",l,r);
update(l, r, 1, k, 1, edges[i].pos);
ans+= (edges[i+1].h - edges[i].h) * Tree[1].len;
}
printf("Test case #%d\n", kase++);
printf("Total explored area: %.2f\n\n", ans);
}
fclose(stdin);
return 0;
}