题目
给定平面上若干矩形,求出被这些矩形覆盖过至少两次的区域的面积.
Input
输入数据的第一行是一个正整数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
这个题和并面积类似,就是把len换成俩len1和len2,然后pushup的时候再改变一下,若不理解,请先理解并面积
这个题好像有问题,题目上说的是给左上角和右下角的点,样例给的是左下角和右上角的点(经过测试,样例是对的)
#include <iostream>
#include<algorithm>
#include<cstdio>
#include<queue>
#include<vector>
#include<cmath>
using namespace std;
typedef long long LL;
const int N=1e4+7;
vector<double>q;
struct edge //存边的信息
{
double x,y1,y2;
int k;
} ma[N*2];
struct node //建线段树
{
int l,r;
int cnt;
double len1,len2;
} tr[N*8];
int cmp(struct edge a,struct edge b) //以x排序
{
return a.x<b.x;
}
int find(double x) //离散化,,找原来y的大小
{
return lower_bound(q.begin(),q.end(),x)-q.begin();
}
void pushup(int u) //更新len,
{
if(tr[u].cnt>=2) //这个区间被覆盖俩次的时候,求len2的值
{
tr[u].len2=q[tr[u].r+1]-q[tr[u].l];
}
else if(tr[u].cnt==1) //如果这个区间被覆盖一次
{ //那么再加上他的俩个儿子被覆盖一次的长度,就是他覆盖俩次的长度
tr[u].len2=tr[u<<1].len1+tr[u<<1|1].len1;
}
//如果这个区间被覆盖0次,那么再加上他的俩个儿子被覆盖俩次次的长度,就是他覆盖俩次的长度
else tr[u].len2=tr[u<<1].len2+tr[u<<1|1].len2;
if(tr[u].cnt>=1) //更新覆盖一次的长度
{
tr[u].len1=q[tr[u].r+1]-q[tr[u].l];
} //如果这个区间没有被覆盖,那么加上他俩儿子被覆盖一次的长度就是他被覆盖一次的长度
else tr[u].len1=tr[u<<1].len1+tr[u<<1|1].len1;
}
void build(int u,int l,int r) //建树
{
tr[u]= {l,r,0,0,0};
if(l!=r)
{
int mid=l+r>>1;
build(u<<1,l,mid);
build(u<<1|1,mid+1,r);
}
}
void change(int u,int l,int r,int k)
{
if(tr[u].l>=l&&tr[u].r<=r)
{
tr[u].cnt+=k; //更新cnt
pushup(u);
return ;
}
int mid=tr[u].l+tr[u].r>>1;
if(l<=mid)change(u<<1,l,r,k);
if(r>mid)change(u<<1|1,l,r,k);
pushup(u);
return ;
}
int main()
{
int n,T=1;
scanf("%d",&T);
while(T--)
{
int n;
q.clear();
scanf("%d",&n);
for(int i=0,j=0; i<n; i++)
{
double x1,x2,y1,y2;
scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
ma[j++]= {x1,y1,y2,1};
ma[j++]= {x2,y1,y2,-1};
q.push_back(y1);
q.push_back(y2);
}
sort(q.begin(),q.end()); //离散化,去重
unique(q.begin(),q.end());
build(1,0,q.size()-2); //以y的区间来建线段树,
//总共是size()-1个点那么就有size()-2个区间,0,代表q[0]到q[1]的区间,q代表q[1]到q[2]的
//区间,,,q是离散化后的y
sort(ma,ma+2*n,cmp);
double ans=0;
for(int i=0; i<2*n; i++)
{
if(i>0)ans+=tr[1].len2*(ma[i].x-ma[i-1].x);
// printf("find ===%d %d\n",find(ma[i].y1),find(ma[i].y2)-1);
change(1,find(ma[i].y1),find(ma[i].y2)-1,ma[i].k);//这里的y2找到离散化后的点后要-1,因为传递的是区间
} //结合上面那个build那里理解,,pushup里面用的时候会+1
printf("%.2lf\n",ans);
}
return 0;
}