覆盖的面积
Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 6458 Accepted Submission(s): 3286
Problem Description
给定平面上若干矩形,求出被这些矩形覆盖过至少两次的区域的面积.
Input
输入数据的第一行是一个正整数T(1<=T<=100),代表测试数据的数量.每个测试数据的第一行是一个正整数N(1<=N<=1000),代表矩形的数量,然后是N行数据,每一行包含四个浮点数,代表平面上的一个矩形的左上角坐标和右下角坐标,矩形的上下边和X轴平行,左右边和Y轴平行.坐标的范围从0到100000.
注意:本题的输入数据较多,推荐使用scanf读入数据.
注意:本题的输入数据较多,推荐使用scanf读入数据.
Output
对于每组测试数据,请计算出被这些矩形覆盖过至少两次的区域的面积.结果保留两位小数.
Sample Input
2 5 1 1 4 2 1 3 3 7 2 1.5 5 4.5 3.5 1.25 7.5 4 6 3 10 7 3 0 0 1 1 1 0 2 1 2 0 3 1
Sample Output
7.63 0.00
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1001;
struct Xpoint{
double x, l, r;
int v;
bool operator < (const Xpoint& e){
return x < e.x;
}
}line[maxn << 1];
struct tree{
int cover;
double len1, len2;
}c[maxn << 4];
double y[maxn << 2];
void build(int o, int l, int r){
c[o].cover = c[o].len1 = c[o].len2 = 0;
if(l == r - 1) return;
int mid = l + r >> 1;
build(o << 1, l, mid);
build(o << 1 | 1, mid, r);
}
void pushup(int o, int l, int r){
if(c[o].cover > 0){
c[o].len1 = y[r] - y[l];
}
else if(l == r - 1){
c[o].len1 = 0;
}
else{
c[o].len1 = c[o << 1].len1 + c[o << 1 | 1].len1;
}
if(c[o].cover > 1){
c[o].len2 = y[r] - y[l];
}
else if(l == r - 1){
c[o].len2 = 0;
}
else if(c[o].cover == 1){
c[o].len2 = c[o << 1].len1 + c[o << 1 | 1].len1; //如果当前被完全覆盖了一层,那么不连续的子区间就是第二层覆盖
}
else c[o].len2 = c[o << 1].len2 + c[o << 1 | 1].len2;
}
void add(int o, int l, int r, int L, int R, int v){
if(l >= R || r <= L) return;
if(l >= L && r <= R){
c[o].cover += v;
pushup(o, l, r);
return;
}
int mid = l + r >> 1;
add(o << 1, l, mid, L, R, v);
add(o << 1 | 1, mid, r, L, R, v);
pushup(o, l, r);
}
int main(){
int n, T;
scanf("%d", &T);
double x1, x2, y1, y2;
while(T--){
scanf("%d", &n);
int tot = 0;
for(int i = 1; i <= n; ++i){
scanf("%lf %lf %lf %lf", &x1, &y1, &x2, &y2);
line[++tot].x = x1;
line[tot].l = y1;
line[tot].r = y2;
line[tot].v = 1;
y[tot] = y1;
line[++tot].x = x2;
line[tot].l = y1;
line[tot].r = y2;
line[tot].v = -1;
y[tot] = y2;
}
build(1, 1, tot);
sort(y + 1, y + 1 + tot);
sort(line + 1, line + 1 + tot);
double ans = 0;
for(int i = 1; i < tot; ++i){
y1 = lower_bound(y + 1, y + 1 + tot, line[i].l) - y;
y2 = lower_bound(y + 1, y + 1 + tot, line[i].r) - y;
add(1, 1, tot, y1, y2, line[i].v);
ans += c[1].len2 * (line[i + 1].x - line[i].x);
}
printf("%.2lf\n", ans);
}
}
/*
题意:
1000个矩形,坐标范围1e5,求所有矩形的总覆盖面积。
思路:
我们把y轴映射到线段树上,离散化一下,按照x的坐标从小到大依次处理所有矩形的平行于y轴的边。
每一个矩形x坐标小的边表示后面这个区域是被覆盖的,直到遇到x大的边结束。那么我们对于所有矩形
左边的边,我们讲其加到线段树的区间上,这样每处理一条边,区间上被覆盖的区间长度可以计算出来,
即这一段y轴的区域是被覆盖的,再利用x算一下这一段的面积。一直处理完所有面积即可。
这一题需要主要的是需要维护两次覆盖,计算覆盖区间时需要分类讨论一下。
*/