Atlantis

 

 
题目大意:给n个矩形,求出矩形面积并
 
经典入门扫描线。首先我们来看什么是扫描线。
 
扫描线,是一条我们构造的一条垂直于坐标轴的线,目的是将矩形面积并的问题分割为求若干矩形的问题。
 

 

如上图,两个矩形相交,红色的线即为我们的扫描线,扫描线可以垂直于y轴也可以垂直于x轴,我们将以垂直于y轴作为标准讲解。

 

如上图,我们当前可以求出蓝色矩形的面积,这是第一块的面积。

 

 

接下来,又求得黄色矩形的面积。

 

 最后,我们求得绿色矩形的面积,所以答案很容易得到为三次求得面积的和。

 要提的是,我们的扫描线其实只有一条,而图中画出两条是为了更好看出我们每次计算的面积是哪一部分。而我们每次扫描一条线的时ans+=(下一条线的高度-当前高度)*当前高度的x的长度。

 
 
以这张图为例,我当前扫描线其实是下方的红线,我的当前高度的长度为该矩形的长,下一条线的高度减去当前高度为矩形的宽。
 
当计算绿色矩形面积时,我们的扫描线为下方红线,很明显下方红线穿过的长度大于上方红线穿过的长度,如果我们还想刚才那样做ans+=。就会有多余面积,为了解决这一问题,我们将矩形的上底和下底用不同标记来表示,通常下底标为1,上底标为-1。当我们扫到标记为-1的边时我们要将这条边减去,同时我们也会有数组来存当前的标记值为多少。
 
代码如下:
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;

int n,m=0;
int mark[2000],lt[2000],rt[2000];
double nex[2000],s[2000];

struct node{
    double l,r,h;
    int f;      //标记上底还是下底
}a[1000];

bool cmp(node a,node b)
{
    return a.h<b.h;
}

void build(int l,int r,int k) 
{
    mark[k]=0,s[k]=0;
    lt[k]=l;rt[k]=r;
    if(l==r-1) return;
    int mid=(l+r)/2;
    build(l,mid,k<<1);
    build(mid,r,k<<1|1);
}

void init()
{
    m=0;
    for(int i=1;i<=n;i++)
    {
        double x1,y1,x2,y2;
        scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
        a[m].l=x1;a[m].r=x2;a[m].h=y1;
        a[m].f=1;nex[m]=x1;m++;
        a[m].l=x1;a[m].r=x2;a[m].h=y2;
        a[m].f=-1;nex[m]=x2;m++;
    }
    sort(a,a+m,cmp);
    sort(nex,nex+m);
    m=unique(nex,nex+m)-nex;
    build(0,m-1,1);
}

void update(int k)
{
    if (mark[k]) s[k]=nex[rt[k]]-nex[lt[k]];
    else if (rt[k]==lt[k]) s[k]=0;
    else s[k]=s[k<<1]+s[k<<1|1];
}

void change(int l,int r,int k,int flag)
{
    if(l<=lt[k]&&r>=rt[k])
    {
        mark[k]+=flag;
        update(k);
        return ;
    }
    int mid=(lt[k]+rt[k])/2;
    if(l>=mid)
    {
        change(l,r,k<<1|1,flag);
    }
    else if(r<=mid)
    {
        change(l,r,k<<1,flag);
    }
    else 
    {
        change(l,r,k<<1,flag);
        change(l,r,k<<1|1,flag);
    }
    update(k);
}

int main()
{
    int cnt=0;
    while(scanf("%d",&n)!=EOF&&n)
    {
        init();
        double ans=0;
        for(int i=0;i<=2*n-1;i++)
        {
            int l=lower_bound(nex,nex+m,a[i].l)-nex;
            int r=lower_bound(nex,nex+m,a[i].r)-nex;
            change(l,r,1,a[i].f);
            ans+=s[1]*(a[i+1].h-a[i].h);
        }
        printf("Test case #%d\n",++cnt);
        printf("Total explored area: %.2f\n\n",ans);
    }
    return 0;
 } 

 

之后有想法会继续写全一点(其实是现在太菜解释不来

 posted on 2019-10-21 19:51  haianx  阅读(225)  评论(0编辑  收藏  举报