zoukankan      html  css  js  c++  java
  • POJ1151Atlantis 矩形面积并 扫描线 线段树

    欢迎访问~原文出处——博客园-zhouzhendong

    去博客园看该题解


    题目传送门 - POJ1151


    题意概括

      给出n个矩形,求他们的面积并。

      n<=100


    题解

      数据范围极小。

      我们分3种算法逐步优化。

     

      算法1: O(n3)

      如果这n个矩形的坐标都是整数,而且比较小,那么我们显然可以用最暴力的方法:一个一个打标记。

      但是不是这样的。

      坐标大小很大,而且是实数。

      然而我们发现差不多,只要先离散化一下,然后再打标记即可。

     

      算法2:O(n2)

      实际上,上面的方法十分慢。如果n的范围到了1000,上面的就无济于事了。

      而实际上,基于上面的打标记的算法,我们可以通过差分的方法n2解决。

      我们通过差分,可以用n2的时间标记,n2的时间判断每一个区域是否被覆盖。

      空间复杂度O(n2)

     

      算法3:O(n logn) 扫描线

      实际上,这类问题的数据范围可以到100000这个级别。

      矩形面积并可以用扫描线算法来解决。先看原理,后面讲具体实现。

      比如下图:

      

      当前我们的扫描线到达了淡黄色部分。

      由于之前没有记录,所以答案不增加。

      然而我们记下当前横向覆盖的长度。

      然后我们到了第二条扫描线,加上原来记录的横向覆盖长度乘以增加的高度就是当前增加的答案。

      然后,我们更新了横向覆盖的长度。

      继续。

      

      然后第三条。现在的横向覆盖长度是两边加起来,所以增加的面积是两块了。

      然后更新横向覆盖的长度,加上了中间的那一条。

      然后继续。

      

      现在有这么长的一条都是被横向覆盖的了。

      所以新增的面积是浅蓝色部分。

      然后我们发现左上那条线是出边,所以要删除这一条线。

      所以横向覆盖的长度为如下:

      

      同理,接下来是:

      

      然后就OK了。

      

      那么具体怎么实现呢?

      我们开一棵线段树来维护!

      在读入之后,我们把所有的横线都拆开,分成下边和上边两类。某一区间在进入下边的时候+1,离开上边的时候-1,所以我们分别给上下边标记+1和-1。

      对于Y,我们离散化一下。

      对于X,我们按照边的X排一个序。

      然后按照刚才那样的处理。

      具体如何维护详见代码。


    代码

    #include <cstring>
    #include <algorithm>
    #include <cstdio>
    #include <cstdlib>
    #include <cmath>
    using namespace std;
    const int N=100+5,M=N*2;
    const double Eps=1e-9;
    int T=0,n,m,tot_Y,tot_s;
    double Y[M];
    struct Segment{
        double x,L,R;
        int v;
        void set(double x_,double L_,double R_,int v_){
            x=x_,L=L_,R=R_,v=v_;
        }
    }s[M];
    struct SegTree{
        int cnt;
        double sum;
    }t[M*4];
    bool cmp_s(Segment a,Segment b){
        return a.x<b.x;
    }
    void build(int rt,int le,int ri){
        t[rt].cnt=0;
        t[rt].sum=0;
        if (le==ri)
            return;
        int mid=(le+ri)>>1,ls=rt<<1,rs=ls|1;
        build(ls,le,mid);
        build(rs,mid+1,ri);
    }
    void pushup(int rt,int le,int ri){
        int ls=rt<<1,rs=ls|1;
        if (t[rt].cnt)
            t[rt].sum=Y[ri+1]-Y[le];
        else if (le==ri)
            t[rt].sum=0;
        else
            t[rt].sum=t[ls].sum+t[rs].sum;
    }
    void update(int rt,int le,int ri,int xle,int xri,int d){
        if (le>xri||ri<xle)
            return;
        if (xle<=le&&ri<=xri){
            t[rt].cnt+=d;
            pushup(rt,le,ri);
            return;
        }
        int mid=(le+ri)>>1,ls=rt<<1,rs=ls|1;
        update(ls,le,mid,xle,xri,d);
        update(rs,mid+1,ri,xle,xri,d);
        pushup(rt,le,ri);
    }
    int find_double(double x){
        int le=1,ri=m,mid;
        while (le<=ri){
            mid=(le+ri)>>1;
            if (abs(x-Y[mid])<Eps)
                return mid;
            if (Y[mid]<x)
                le=mid+1;
            else
                ri=mid-1;
        }
    }
    int main(){
        while (scanf("%d",&n)&&n){
            tot_Y=tot_s=0;
            for (int i=1;i<=n;i++){
                double xA,yA,xB,yB;
                scanf("%lf%lf%lf%lf",&xA,&yA,&xB,&yB);
                if (yB-yA<Eps||xB-xA<Eps)
                    continue;
                Y[++tot_Y]=yA,Y[++tot_Y]=yB;
                s[++tot_s].set(xA,yA,yB,1);
                s[++tot_s].set(xB,yA,yB,-1);
            }
            sort(Y+1,Y+tot_Y+1);
            sort(s+1,s+tot_s+1,cmp_s);
            m=1;
            for (int i=2;i<=tot_Y;i++)
                if (Y[i]-Y[i-1]>Eps)
                    Y[++m]=Y[i];
            build(1,1,m);
            double ans=0;
            for (int i=1;i<=tot_s;i++){
                ans=ans+(s[i].x-s[i-1].x)*t[1].sum;
                int L=find_double(s[i].L);
                int R=find_double(s[i].R);
                update(1,1,m,L,R-1,s[i].v);
            }
            printf("Test case #%d
    Total explored area: %.2lf
    
    ",++T,ans);
        }
        return 0;
    }
  • 相关阅读:
    耗油
    [深入Python]Alex Martelli的Borg类
    Python Frame objects 和Traceback objects
    2012美国汽车销量排行
    Python中统计函数的运行耗时
    Python显示函数的调用者
    Python的内置函数map
    [深入Python]简单事情复杂化:Python计算阶乘
    Solaris查看线程
    VVR常用操作
  • 原文地址:https://www.cnblogs.com/zhouzhendong/p/POJ1151.html
Copyright © 2011-2022 走看看