题意
给你n个矩形,算出他们覆盖了多少面积
思路
总结一下扫描线的套路
把矩形的上下边 按照 左端点的x坐标 右端点的x坐标 高度 为上位边还是下位边存起来
当作扫描线 根据高度排序,从低到高,也就是y坐标
把所有x坐标都提取出来 排序离散化
线段树维护的节点 为x坐标某个区间内左端点 右端点 下位边的总长度 下位边的数量
如果扫描线下标为1~m 循环1 ~ m-1
m条扫描线 循环m-1次 每次先更新当前下位边总长度 算出当前扫描线与下一条扫描线的差值*当前下位边总长度 即为两条扫描线覆盖的面积
学习自某位dalao博客的扫描线思想
AC_code
#include<bits/stdc++.h>
using namespace std;
const int maxn = 205;
struct node {
double l, r, h;//左端点 右端点 高度
int d;
//标记上位边 还是下位边
//1为下位边 -1为上位边
node() {}
node(double l,double r, double h, int d):l(l),r(r),h(h),d(d) {}
bool operator < (const node &a)const {
return h<a.h;
}
} line[maxn]; //扫描线
double x[maxn];//离散化过的x坐标
int cnt[maxn<<2];//标记某个区间下位边数量
double sum[maxn<<2];//标记某个区间下位边长度
//更新的节点 更新的左端点 更新的右端点
void pushup(int i,int l,int r) {
if(cnt[i]) {
sum[i] = x[r+1] - x[l];
} else {
sum[i] = sum[i<<1] + sum[i<<1|1];
}
}
// 更新的区间左端点 更新的区间右端点 增加的下位边的数量 更新的节点 更新到的左端点 更新到的右端点
void update(int ql, int qr, int v, int i, int l, int r) {
if(ql <= l && qr >= r) {
cnt[i] += v;
pushup(i, l, r);
return;
}
int mid = (l + r) / 2;
if(ql <= mid) {
update(ql, qr, v, i<<1, l, mid);
}
if(qr > mid) {
update(ql, qr, v, i<<1|1, mid+1, r);
}
pushup(i, l, r);
}
int main() {
int cas = 1;
int t;
while(~scanf("%d",&t)) {
if(t == 0) {
break;
}
memset(cnt, 0, sizeof(cnt));
memset(sum, 0, sizeof(sum));//初始化 相当于bulid_tree
int n = 0, m = 0;
double x1, x2, y1, y2;
for(int i = 0; i < t; i++) {
scanf("%lf %lf %lf %lf", &x1, &y1, &x2, &y2);
x[++n] = x1;
x[++n] = x2;
line[++m] = node(x1, x2, y1, 1);//下位边
line[++m] = node(x1, x2, y2, -1);//上位边
}
sort(x+1, x+1+n);
sort(line+1, line+1+m);
int k = unique(x+1, x+n+1) - x - 1;//离散化
double ans = 0.0;
for(int i = 1; i < m; i++) { //m条扫描线 循环m-1次即可
int l = lower_bound(x+1, x+k+1, line[i].l) - x;
int r = lower_bound(x+1, x+k+1, line[i].r) - x - 1;//这里记得减1
if(l <= r) {
update(l, r, line[i].d, 1, 1, k-1);
}
//sum[1]代表总的下位边长度
ans += sum[1] * (line[i+1].h - line[i].h);
}
printf("Test case #%d\nTotal explored area: %.2f\n\n", cas++, ans);
}
return 0;
}