求矩形面积的并,这个题应该是线段树刚刚出现在竞赛时要做的题。
这个题的主要思想就是扫描,我们将所有矩形竖直方向的两条线段,都拿出来排序,然后扫描用线段树维护覆盖的线段长度即可。
对于如上的矩形给所有竖直线段排序后就可以得到下面的图
我们可以观察到从一条线段到下一条线段之前竖直方向的覆盖长度a都不变,而这两条线段之间的距离为b,那么这两条线段之间的面积表示为a * b。
邻近的两条竖直的线段将整个图形分解成若干个部分,我们按上面的方法计算的面积的和就是面积的并了。
为了快速得到竖直方向的覆盖情况,我们用线段树来维护。
比如上图,第一条线段覆盖了a1,到下一条线段的距离为b1,计算面积;第二条与第一条线段共同覆盖了a2,到下一条线段的距离为b2;第三条线段退出覆盖,覆盖的长度为a3(a3==a1),到下一线段的距离为b3....
那么总面积为a1 * b1 + a2 * b2 + a3 * b3 ...
就可以输出答案了。
代码很丑,慢慢看。
#include<cstdio>
#include<algorithm>
using namespace std;
struct node {
double x, y;
};
struct edge {
double x;
int st, ed;
int wt;
bool operator < (const edge &rhs) const {
return x < rhs.x;
}
};
const int MAXN = 500;
int n;
node A[MAXN + 10], B[MAXN + 10];
int nn;
edge Edge[MAXN + 10];
int mx;
double val[MAXN + 10];
struct seg {
int l, r;
int sig;
double cnt;
inline double length() { return val[r] - val[l]; }
void update(seg &lch, seg &rch) {
if(sig) cnt = length();
else {
if(l + 1 >= r) cnt = 0;
else cnt = lch.cnt + rch.cnt;
}
}
} Tree[MAXN * 4 + 10];
void Build(int u, int l, int r) {
seg &cur = Tree[u];
cur.l = l, cur.r = r;
cur.cnt = cur.sig = 0;
if(l + 1 >= r) return ;
int mid = (l + r) / 2;
Build(u * 2, l, mid);
Build(u * 2 + 1, mid, r);
}
void Ins(int u, int l, int r, int x) {
seg &cur = Tree[u], &lch = Tree[u * 2], &rch = Tree[u * 2 + 1];
if(cur.l >= r || cur.r <= l) return ;
else if(l <= cur.l && cur.r <= r) cur.sig += x;
else {
Ins(u * 2, l, r, x);
Ins(u * 2 + 1, l, r, x);
}
cur.update(lch, rch);
}
double work() {
mx = nn = 0;
for(int i = 1; i <= n; i++) val[++mx] = A[i].y, val[++mx] = B[i].y;
sort(val + 1, val + 1 + mx);
mx = unique(val + 1, val + 1 + mx) - val - 1;
for(int i = 1; i <= n; i++) {
int y1 = lower_bound(val + 1, val + 1 + mx, A[i].y) - val, y2 = lower_bound(val + 1, val + 1 + mx, B[i].y) - val;
Edge[++nn] = (edge){A[i].x, y1, y2, 1};
Edge[++nn] = (edge){B[i].x, y1, y2, -1};
}
sort(Edge + 1, Edge + 1 + nn);
double ans = 0;
double Last = 0;
Build(1, 1, mx);
for(int i = 1; i <= nn; i++) {
if(i != 1) ans += Tree[1].cnt * (Edge[i].x - Last);
Last = Edge[i].x;
Ins(1, Edge[i].st, Edge[i].ed, Edge[i].wt);
}
return ans;
}
int main() {
int kase = 0;
while(scanf("%d", &n) == 1 && n) {
for(int i = 1; i <= n; i++) {
scanf("%lf%lf", &A[i].x, &A[i].y);
scanf("%lf%lf", &B[i].x, &B[i].y);
}
printf("Test case #%d\nTotal explored area: %.2f\n\n", ++kase, work());
}
return 0;
}
相应的我们也会求矩形面积的交、并、以及周长了。
poj1177 求轮廓周长
hdu1255 求面积的交
hdu4419 也可以算求矩形面积的交吧
hdu4052 可以转化模型为求矩形面积的并