HDU 1255 覆盖的面积 (求矩形面积的交)

覆盖的面积

Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)

Description
给定平面上若干矩形,求出被这些矩形覆盖过至少两次的区域的面积.

 

 

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

 题意:求矩形面积的交。

分析:就是矩形面积并的一个升级版,在求并时,重复多少次我们并没有管,现在要叫我们求至少相交2次的面积,为此可以在结构体中增加一个变量ss,表示覆盖2次及以上的区间长度,s表示覆盖一次的长度,改变的就只有计算长度的那个函数,如何计算ss:

 

1.cnt>1 : 说明该区间被覆盖两次或以上,那么长度就可以直接计算,就是该区间的长度

 

剩下的情况就是cnt=1或cnt=0

 

2.先看叶子节点,因为是叶子没有孩子了,所以被覆盖两次货以上的长度就是0(无论cnt=1或cnt=0都是0,因为是叶子。。。)

 

3.不是叶子节点 ,且cnt=1.注意这里,cnt=1确切的意义是什么,应该是,可以确定,这个区间被完全覆盖了1次,而有没有被完全覆盖两次或以上则不知道无法确定,那么怎么怎么办了,只要加上t[lch].s + t[rch].s  即,看看左右孩子区间被覆盖了一次或以上的长度,那么叠加在双亲上就是双亲被覆盖两次或以上的长度

 

3.不是叶子节点,且cnt=0,确切的意义应该是不完全不知道被覆盖的情况(不知道有没有被覆盖,被覆盖了几次,长度是多少都不知道),这种情况,只能由其左右孩子的信息所得

 

t[lch].ss + t[rch].ss  , 即直接将左右孩子给覆盖了两次或以上的长度加起来。

#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
using namespace std;

const int MAXN = 1100;
struct Node
{
    int l,r;
    double cnt;//该节点的覆盖情况
    double s,ss;
}segTree[2*MAXN*4];
struct Segment
{
    double l,r,h;
    int f;
}ss[MAXN*2];
double pos[MAXN*2];

bool cmp(const Segment& aa,const Segment& bb)
{
    return aa.h<bb.h;
}
void build(int id,int l,int r)
{
    segTree[id].l=l;
    segTree[id].r=r;
    segTree[id].cnt=0;
    segTree[id].s=0;
    segTree[id].ss=0;
    if(l==r) return;
    int mid=(l+r)/2;
    build(id*2,l,mid);
    build(id*2+1,mid+1,r);
}
void calen(int id)
{
    if(segTree[id].cnt)
        segTree[id].s=pos[segTree[id].r+1]-pos[segTree[id].l];
    else if(segTree[id].l==segTree[id].r) segTree[id].s=0;
    else segTree[id].s=segTree[id*2].s+segTree[id*2+1].s;
    if(segTree[id].cnt>1)
        segTree[id].ss=pos[segTree[id].r+1]-pos[segTree[id].l];
    else if(segTree[id].l==segTree[id].r) segTree[id].ss=0;
    else if(segTree[id].cnt==1)
        segTree[id].ss=segTree[id*2].s+segTree[id*2+1].s;
    else segTree[id].ss=segTree[id*2].ss+segTree[id*2+1].ss;
}
void update(int id,int l,int r,int val)
{
    if(segTree[id].l==l&&segTree[id].r==r)
    {
        segTree[id].cnt+=val;
        calen(id);
        return;
    }
    int mid=(segTree[id].l+segTree[id].r)/2;
    if(l>mid) update(id*2+1,l,r,val);
    else if(r<=mid) update(id*2,l,r,val);
    else
    {
        update(id*2,l,mid,val);
        update(id*2+1,mid+1,r,val);
    }
    calen(id);
}

int main()
{
    int T;
    int n;
    double x1,y1,x2,y2;
    scanf("%d",&T);
    while(T--)
    {
        int t=1;
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
        {
            scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
            ss[t].l=x1,ss[t].r=x2,ss[t].h=y1,ss[t].f=1,pos[t]=x1,t++;
            ss[t].l=x1,ss[t].r=x2,ss[t].h=y2,ss[t].f=-1,pos[t]=x2,t++;
        }
        sort(ss+1,ss+t,cmp);
        sort(pos+1,pos+t);
        //for(int i=1; i<t; i++) printf("%.2lf %.2lf  %.2lf\n",ss[i].l,ss[i].r,ss[i].h);
        int m=2;
        for(int i=2;i<t;i++)
            if(pos[i]!=pos[i-1])
                pos[m++]=pos[i];
        build(1,1,m-1);
        double ans=0;
        for(int i=1;i<t;i++)
        {
            int l=lower_bound(pos+1,pos+m,ss[i].l)-pos;
            int r=lower_bound(pos+1,pos+m,ss[i].r)-pos-1;
            //cout<<l<<" "<<r<<endl;
            update(1,l,r,ss[i].f);
            ans+=(ss[i+1].h-ss[i].h)*segTree[1].ss;
        }
        printf("%.2lf\n",ans);
    }
    return 0;
}

 

 

posted @ 2016-08-05 22:16  季末Despair  阅读(303)  评论(0编辑  收藏  举报