HDU - 1255 覆盖的面积【扫描线】

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/niiick/article/details/81986041

Time limit 5000 ms
Memory limit 32768 kB
给定平面上若干矩形,求出被这些矩形覆盖过至少两次的区域的面积.
这里写图片描述

Input

输入数据的第一行是一个正整数T(1<=T<=100),代表测试数据的数量.每个测试数据的第一行是一个正整数N(1<=N<=1000),代表矩形的数量,然后是N行数据,每一行包含四个浮点数,代表平面上的一个矩形的左上角坐标和右下角坐标,矩形的上下边和X轴平行,左右边和Y轴平行.坐标的范围从0到100000.

注意:本题的输入数据较多,推荐使用scanf读入数据.

Output

对于每组测试数据,请计算出被这些矩形覆盖过至少两次的区域的面积.结果保留两位小数.


题目分析

多个矩形的面积交
在求面积并的扫描线基础上扩展一下即可

扫描线—学习笔记

l e n [ 0 ] [ p ] 记录 结点p对应区间内至少被覆盖一次的长度
l e n [ 1 ] [ p ] 记录 结点p对应区间内至少被覆盖两次的长度

求面积并的上推代码为

void pushup(int p,int s,int t)
{
    if(cov[p]>0) len[p]=pos[t+1]-pos[s];
    else if(s==t) len[p]=0;
    else len[p]=len[p<<1]+len[p<<1|1];
}

我们在此基础上扩展
加入 c o v [ p ] >= 2 的情况
并在原来三种情况的基础上加入 l e n [ 1 ] [ ] 的更新

void pushup(int p,int s,int t)
{
    if(cov[p]>=2) len[0][p]=len[1][p]=pos[t+1]-pos[s];//加入cov[p]>=2的情况
    else if(cov[p]==1)
    {
        len[0][p]=pos[t+1]-pos[s];
        if(s==t) len[1][p]=0;//加入len[1][]的更新
        else len[1][p]=len[0][p<<1]+len[0][p<<1|1];
    }
    else if(s==t) len[0][p]=len[1][p]=0;//原来只有len[0][p]=0;
    else//cov[p]==0也加入len[1][]的更新
    len[0][p]=len[0][p<<1]+len[0][p<<1|1],
    len[1][p]=len[1][p<<1]+len[1][p<<1|1];
}

#include<iostream>
#include<cmath>
#include<algorithm>
#include<queue>
#include<cstring>
#include<cstdio>
#include<map>
using namespace std;
typedef double dd;

int read()
{
    int x=0,f=1;
    char ss=getchar();
    while(ss<'0'||ss>'9'){if(ss=='-')f=-1;ss=getchar();}
    while(ss>='0'&&ss<='9'){x=x*10+ss-'0';ss=getchar();}
    return x*f;
}

const int maxn=2010;
int t,n;
int tot1,tot2,cnt;
struct node{dd x,y1,y2;int k;}rem[maxn];
bool cmp(node a,node b){return a.x<b.x;}
dd a[maxn],pos[maxn];
dd len[2][maxn<<2],ans;
int cov[maxn<<2];

void init()
{
    cnt=tot1=tot2=0; ans=0;
    memset(len,0,sizeof(len));
    memset(cov,0,sizeof(cov));
}

void pushup(int p,int s,int t)
{
    if(cov[p]>=2) len[0][p]=len[1][p]=pos[t+1]-pos[s];
    else if(cov[p]==1)
    {
        len[0][p]=pos[t+1]-pos[s];
        if(s==t) len[1][p]=0;
        else len[1][p]=len[0][p<<1]+len[0][p<<1|1];
    }
    else if(s==t) len[0][p]=len[1][p]=0;
    else
    len[0][p]=len[0][p<<1]+len[0][p<<1|1],
    len[1][p]=len[1][p<<1]+len[1][p<<1|1];
}

void update(int ll,int rr,int s,int t,int p,int v)
{
    if(ll<=s&&t<=rr){ cov[p]+=v; pushup(p,s,t); return;}
    int mid=s+t>>1;
    if(ll<=mid) update(ll,rr,s,mid,p<<1,v);
    if(rr>mid) update(ll,rr,mid+1,t,p<<1|1,v);
    pushup(p,s,t);
}

int main()
{
    t=read();
    while(t--)
    {
        n=read(); init();
        for(int i=1;i<=n;i++)
        {
            dd x1,y1,x2,y2;
            scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
            a[++tot1]=y1; a[++tot1]=y2;
            rem[++tot2].x=x1; rem[tot2].y1=y1;  rem[tot2].y2=y2; rem[tot2].k=1;
            rem[++tot2].x=x2; rem[tot2].y1=y1;  rem[tot2].y2=y2; rem[tot2].k=-1;
        }

        sort(a+1,a+1+tot1);
        for(int i=1;i<=tot1;++i)
        if(i==1||a[i]!=a[i-1])
        pos[++cnt]=a[i];

        sort(rem+1,rem+1+tot2,cmp); 
        for(int i=1;i<tot2;i++)
        {
            int ll=lower_bound(pos+1,pos+1+cnt,rem[i].y1)-pos;
            int rr=lower_bound(pos+1,pos+1+cnt,rem[i].y2)-pos;
            update(ll,rr-1,1,cnt,1,rem[i].k);
            ans+=len[1][1]*(rem[i+1].x-rem[i].x);
        }
        printf("%.2lf\n",ans);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/niiick/article/details/81986041
今日推荐