HDU1542 Atlantis (矩形面积并,扫描线+离散化+线段树)

题意

给定n个矩形的左下坐标和右上坐标。求这n个矩形的面积的并集。

解题

扫描线:
这个还是很好理解的。n个矩形有2n条分割线,从下到上扫描,每次扫描到分割线都累加一次面积。即通过分割线将矩形并分成2n-1割图形。
离散化:
每次累加面积是通过两条分割线的高度差*被覆盖的区间长度完成的。所以我们要维护这个被覆盖的区间。因为x坐标的值达到了1e5的数量级,而矩形的数量级才1e2.故对x坐标离散化。即排序去重后,用值的下标去代替值。
线段树:
这次要用线段树去维护“线段”,所以叶子结点是一个“最小”的线段。并且,如果结点p维护的区间为[l,r],那么其左儿子和右儿子所维护的区间分别为[l,mid],[mid,r]。mid=(l+r)/2.注意结点所维护的区间与常规的区别,其他的就是常规操作了。

AC代码

//31ms 1.8MB
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#define lson p<<1
#define rson p<<1|1
using namespace std;

const int maxn=300;
struct node
{
    int l,r;//线段树所维护的区间
    int add;//add为1表示加一次覆盖,为-1表示减一次覆盖
    double sum;//对应的被覆盖的长度
}T[maxn<<2];
struct line///从下到上扫描
{
    double h,L,R;//高度和左右端点
    int mark;//标记为1表示下边,为-1表示上边
    bool operator<(const line &o)const
    {
        return h<o.h;
    }
}li[maxn];
double pos[maxn];
void up(int p)
{
    //全部覆盖
    if(T[p].add>0) T[p].sum=pos[T[p].r-1]-pos[T[p].l-1];//长度是对应在pos数组中的值的差
    //不是线段树所维护的区间长度
    else if(T[p].l==T[p].r) T[p].sum=0;//不全部覆盖且是叶子结点,一定没有被覆盖的部分
    else T[p].sum=T[lson].sum+T[rson].sum;//不全部覆盖且是非叶子结点,可能有部分被覆盖
}
void build(int p,int l,int r)
{
    T[p].add=0;T[p].sum=0;
    T[p].l=l,T[p].r=r;
    if(l+1==r) return ;///注意叶子结点是一个长度为1的线段
    int mid=(l+r)>>1;
    build(lson,l,mid);
    build(rson,mid,r);///注意是mid,不是mid+1
}
void update(int p,int x,int y,int c)
{
    if(T[p].l==x && T[p].r==y)
    {
        T[p].add+=c;
        up(p);
        return ;
    }
    int mid=(T[p].l+T[p].r)>>1;
    if(y<=mid) update(lson,x,y,c);
    else if(x>=mid) update(rson,x,y,c);///注意是>=mid,不是>mid
    else
    {
        update(lson,x,mid,c);
        update(rson,mid,y,c);///注意是mid,不是mid+1
    }
    up(p);
}

int main()
{
    int n,kase=0;;
    while(~scanf("%d",&n) && n)
    {
        int cnt=0,d=0;
        for(int i=0;i<n;i++)
        {
            double x1,y1,x2,y2;
            scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
            pos[d++]=x1;
            pos[d++]=x2;
            li[cnt].h=y1;
            li[cnt].L=x1;
            li[cnt].mark=1;
            li[cnt++].R=x2;
            li[cnt].h=y2;
            li[cnt].L=x1;
            li[cnt].mark=-1;
            li[cnt++].R=x2;
        }
        sort(li,li+cnt);
        sort(pos,pos+d);
        int m=unique(pos,pos+d)-pos;
        build(1,1,m);
        double ans=0;
        for(int i=0;i<cnt;i++)
        {
            int l=lower_bound(pos,pos+m,li[i].L)-pos+1;
            int r=lower_bound(pos,pos+m,li[i].R)-pos+1;
            ans+=i==0?0:(li[i].h-li[i-1].h)*T[1].sum;
            update(1,l,r,li[i].mark);
        }
        printf("Test case #%d\n",++kase);
        printf("Total explored area: %.2lf\n\n",ans);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_37685156/article/details/80722794