链接:戳这里
覆盖的面积
Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Problem Description
给定平面上若干矩形,求出被这些矩形覆盖过至少两次的区域的面积.

输入数据的第一行是一个正整数T(1<=T<=100),代表测试数据的数量.每个测试数据的第一行是一个正整数N(1<=N<=1000),代表矩形的数量,然后是N行数据,每一行包含四个浮点数,代表平面上的一个矩形的左上角坐标和右下角坐标,矩形的上下边和X轴平行,左右边和Y轴平行.坐标的范围从0到100000.
注意:本题的输入数据较多,推荐使用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
思路:
在矩形面积并的基础上,加一个存至少交两次的权值的数组
分析一下矩形面积并的时候,tr[root]存的是当前x轴区间是否被覆盖,这里注意到一个点,就是tr[root]=1只能确定[l,r]被完全覆盖至少一次,但是子区间可能有覆盖超过两次的。简单分析下吧
tr[root]>=2:区间[l,r]被完全覆盖至少两次以上。即two[root]=one[root]=one[root*2]+one[root*2+1]
tr[root]=1:当前区间被完全覆盖至少一次,那么覆盖一次的答案one[root]=X[r+1]-X[l],覆盖两次怎么算呢。我们已知整个区间[l,r]至少被覆盖一次,那么子区间至少覆盖一次的[l,mid],[mid+1,r] 也就是子区间至少被覆盖两次了。这里画画线段树就出来了。two[root]=one[root*2]+one[root*2+1]
tr[root]=0:当前区间[l,r]没有被完全覆盖过,所以更新子区间的答案就可以了
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<string>
#include<vector>
#include <ctime>
#include<queue>
#include<set>
#include<map>
#include<stack>
#include<iomanip>
#include<cmath>
#include<bitset>
#define mst(ss,b) memset((ss),(b),sizeof(ss))
///#pragma comment(linker, "/STACK:102400000,102400000")
typedef long long ll;
typedef long double ld;
#define INF (1ll<<60)-1
#define Max 1e9
using namespace std;
struct Line{
double x1,x2,y;
int f;
Line(double x1=0,double x2=0,double y=0,int f=0):x1(x1),x2(x2),y(y),f(f){}
bool operator < (const Line &a)const{
if(y==a.y) return f>a.f;
return y<a.y;
}
}L[50010];
double X[50010];
double one[100010],two[100010];
int tr[100010];
void build(int root,int l,int r){
if(l==r) {
tr[root]=0;
one[root]=0;
two[root]=0;
return ;
}
int mid=(l+r)/2;
build(root*2,l,mid);
build(root*2+1,mid+1,r);
one[root]=one[root*2]+one[root*2+1];
two[root]=two[root*2]+two[root*2+1];
tr[root]=tr[root*2]+tr[root*2+1];
}
void pushup(int root,int l,int r){
if(tr[root]>=2){
two[root]=one[root]=X[r+1]-X[l];
return ;
} else if(tr[root]==1){
one[root]=X[r+1]-X[l];
if(l==r) two[root]=0;
else two[root]=one[root*2]+one[root*2+1];
} else {
if(l==r) one[root]=two[root]=0;
else {
two[root]=two[root*2]+two[root*2+1];
one[root]=one[root*2]+one[root*2+1];
}
}
}
void update(int root,int l,int r,int x,int y,int v){
if(x==l && y==r) {
//printf("l=%d r=%d\n",l,r);
tr[root]+=v;
pushup(root,l,r);
return ;
}
int mid=(l+r)/2;
if(y<=mid) update(root*2,l,mid,x,y,v);
else if(x>mid) update(root*2+1,mid+1,r,x,y,v);
else {
update(root*2,l,mid,x,mid,v);
update(root*2+1,mid+1,r,mid+1,y,v);
}
pushup(root,l,r);
}
int main(){
int T,n,m,cnt;
double x1,y1,x2,y2;
scanf("%d",&T);
while(T--){
scanf("%d",&n);
m=0;
for(int i=1;i<=n;i++){
scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
L[++m]=Line(x1,x2,y1,1);
X[m]=x1;
L[++m]=Line(x1,x2,y2,-1);
X[m]=x2;
}
sort(L+1,L+m+1);
sort(X+1,X+m+1);
int cnt=unique(X+1,X+m+1)-(X+1);
build(1,1,cnt);
double ans=0;
int l=lower_bound(X+1,X+cnt+1,L[1].x1)-X;
int r=lower_bound(X+1,X+cnt+1,L[1].x2)-X-1;
update(1,1,cnt,l,r,L[1].f);
//printf("%d %d\n",l,r);
for(int i=2;i<=m;i++){
if(i>2) ans+=(L[i].y-L[i-1].y)*two[1];
l=lower_bound(X+1,X+cnt+1,L[i].x1)-X;
r=lower_bound(X+1,X+cnt+1,L[i].x2)-X-1;
if(l<=r) update(1,1,cnt,l,r,L[i].f);
//printf("%d %d\n",l,r);
}
printf("%.2f\n",ans);
}
return 0;
}