N(N<=1e3)个矩形,每个矩形提供左下角(x1,y1)和右上角(x2,y2)的点
四个坐标均为浮点数,且在0到1e5之间
求被矩形覆盖过至少两次的区域的面积,结果保留两位小数
http://cache.baiducontent.com/c?m=9d78d513d9d431a54f9d94697d1cc0171c4381132ba7d7020ed28449e3732a405011e7ac57520770a5d27c165bf90e4bea812172411420c698c88f4dc9fcd27620d26172325d914061ce04ea8e0332c157c106b9f144b2fbe732e4ff8f8cc22e44ca256521c4a7d7474209c16ef7103ae6ac8e48620556e5b3&p=c057c816d9c106b742bd9b7d0d108d&newp=882a9645d0815afc57ef8e2415558f231610db2151d7d601298ffe0cc4241a1a1a3aecbf23291202d9ce766c05ab4c5cecf03c70360234f1f689df08d2ecce7e6d93&user=baidu&fm=sc&query=%B8%B2%B8%C7%B5%C4%C3%E6%BB%FD+HDU+%2D+1255&qid=e54c0cad0002fb6e&p1=3
其实就是cnt值的区别
当求矩形面积并的时候,cnt>0的答案就会计算在内
而算矩形面积交的时候,cnt>=2的答案才会被计算在内
注意cnt==1向cnt==2的转化,此时,父节点多了一条边而使得子节点的cnt==1的情形变为cnt==2的情形
所以每个节点内保存两个值,一个len2代表下面有两条矩形底边的长度,len1代表下面有一条矩形底边的长度
len1的判断和矩形面积并是一样的,len2在cnt>=2的时候也是一样的,只特判cnt==1的情形即可
核心在于pushup的写法,剩下的基本是一样的,
注意正确的写法,使得不存在没有意义的p<<1和p<<1|1
#include
#include
#include
#include
#include
#include
using namespace std;
const int maxn=2005;
int cas,n,now;
double ans;
double x[maxn];
double x1,y1,x2,y2;
struct node
{
int l,r;
double len2,len1;//被覆盖两次的长度,被覆盖一次的长度
int cnt;//当前有cnt条重叠的下线段
}e[maxn*5];
struct edge
{
double l,r,h;//当前线段的左界,右界,高度
int op;//矩形op==1是下线段,-1是上线段
edge(){}
edge(double ll,double rr,double hh,int o):l(ll),r(rr),h(hh),op(o){}
friend bool operator<(edge a,edge b){return a.h1)e[p].len2=e[p].len1=x[e[p].r+1]-x[e[p].l];//[l,r)的线段由[l,r-1]表示,但长度仍为[l,r]的长度
//当前父覆盖了1边 考虑让子的不完整1边变为不完整2边
/*
形如
-------- e[p].cnt++;
-- -- e[p<<1].cnt=e[p<<1|1].cnt=1
*/
else if(e[p].cnt==1)
{
if(e[p].l==e[p].r)e[p].len2=0;
else e[p].len2=e[p<<1].len1+e[p<<1|1].len1;
e[p].len1=x[e[p].r+1]-x[e[p].l];
}
else
{
if(e[p].l==e[p].r)e[p].len2=e[p].len1=0;
else
{
e[p].len2=e[p<<1].len2+e[p<<1|1].len2;
e[p].len1=e[p<<1].len1+e[p<<1|1].len1;
}
}
}
void update(int p,int ql,int qr,int op)
{
if(ql<=e[p].l&&e[p].r<=qr)
{
e[p].cnt+=op;
pushup(p);
return;
}
int mid=(e[p].l+e[p].r)/2;
if(ql<=mid)update(p<<1,ql,qr,op);
if(qr>mid)update(p<<1|1,ql,qr,op);
pushup(p);
}
int main()
{
scanf("%d",&cas);
while(cas--)
{
scanf("%d",&n);
for(int i=1;i<=n;++i)//1到2*n
{
scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
x[2*i-1]=x1;
x[2*i]=x2;
g[2*i-1]=edge(x1,x2,y1,1);
g[2*i]=edge(x1,x2,y2,-1);
}
sort(x+1,x+2*n+1);
now=1;
for(int i=2;i<=2*n;++i)//强制去重x数组
if(x[i]!=x[now])x[++now]=x[i];
build(1,1,now);
sort(g+1,g+2*n+1);
ans=0;
for(int i=1;i<=2*n-1;++i)
{
int l=lower_bound(x+1,x+now+1,g[i].l)-x;
int r=lower_bound(x+1,x+now+1,g[i].r)-x;
//[l,l+1)代表线段l,边权线段比点少一个 3个点2条边
//[l,r)内有线段r-l条,故用[l,r-1]来代替
//每个线段对应一个标号
update(1,l,r-1,g[i].op);
//printf("[%d]:%lf [%d]:%lf\n",i+1,g[i+1].h,i,g[i].h);
//printf("e[1].len2:%lf\n",e[1].len2);
ans+=(g[i+1].h-g[i].h)*e[1].len2;
}
printf("%.2lf\n",ans);
}
return 0;
}