• [POJ1151][HDU1542]Atlantis(线段树,扫描线)


    英文题面,我就只放个传送门了。

    Solution

       题意是算矩形面积并,这是扫描线算法能解决的经典问题。

      算法的大致思想是,把每一个矩形拆成上边下边(以下称作扫描线),每条扫描线有四个参数l,r,h,v。l和r为它的左右端点的横坐标,h为扫描线的纵坐标,v下面再解释。

      然后把扫描线按h从小到大排序,想一想,所有相邻扫描线之间的有效面积(即被矩形覆盖的面积)加起来是不是就是ans?

      怎么求呢?我们从下往上处理,设当前处理到第i条扫描线,设第i条扫描线与第i+1条扫描线之间的有效面积为s,那么s=(h[i+1]-h[i])*此时x轴被覆盖的长度。

      考虑用线段树来维护这个“x轴被覆盖的长度“,处理到第i条扫描线时,就把区间[l[i],r[i]]覆盖一次。但是这个覆盖是有时限的,当扫到某一条上边时,它对应的下边所产生的覆盖就应该被消去。

      为了方便地处理,我们把下边的v值设为1,上边的v值设为-1,这样修改时直接把区间[l[i],r[i]]的覆盖次数加v就好了。

      具体实现时,x坐标要离散化,线段树中用cnt来表示区间被覆盖的次数,sum来表示区间(当然都是在x轴上)内的覆盖长度。

      注意两点:

    1. 线段树上一个叶子节点i实际上表示的是x轴上[i,i+1]这一段,因此线段树只需要n-1个叶子节点。
    2. 由于我们只需要查询sum[1],所以update找到需修改的区间可以直接pushup,并且不用pushdown。

    Code

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    const int N=220;
    struct line{
        double l,r,h;int v;
        line(){}
        line(double a,double b,double c,int d):l(a),r(b),h(c),v(d){}
        bool operator < (const line &tmp)const{return h<tmp.h;}
    }L[N];
    int cnt[N<<2];
    double X[N],sum[N<<2];
    #define tl id<<1
    #define tr id<<1|1
    #define mid ((l+r)>>1)
    #define lson tl,l,mid
    #define rson tr,mid+1,r
    void pushup(int id,int l,int r){
        if(cnt[id]) sum[id]=X[r+1]-X[l];
        else if(l==r) sum[id]=0;
        else sum[id]=sum[tl]+sum[tr];
    }
    void update(int id,int l,int r,int ll,int rr,int v){
        if(ll<=l&&r<=rr){
            cnt[id]+=v;
            pushup(id,l,r);
            return ;
        }
        if(ll>mid) update(rson,ll,rr,v);
        else if(rr<=mid) update(lson,ll,rr,v);
        else update(lson,ll,rr,v),update(rson,ll,rr,v);
        pushup(id,l,r);
    }
    int n,m,cas;
    int main(){
        while(~scanf("%d",&n)&&n){
            m=0;memset(cnt,0,sizeof cnt);memset(sum,0,sizeof sum);
            for(int i=0;i<n;++i){
                double a,b,c,d;
                scanf("%lf%lf%lf%lf",&a,&b,&c,&d);
                L[m]=line(a,c,b,1);
                X[m++]=a;
                L[m]=line(a,c,d,-1);
                X[m++]=c;
            } 
            sort(&L[0],&L[m]);
            sort(&X[0],&X[m]);n=unique(&X[0],&X[m])-X;
            double s=0;
            for(int i=0;i<m;++i){
                int l=lower_bound(&X[0],&X[n],L[i].l)-X,r=lower_bound(&X[0],&X[n],L[i].r)-X-1;    
                update(1,0,n-1,l,r,L[i].v);
                s+=sum[1]*(L[i+1].h-L[i].h);
            }
            printf("Test case #%d
    Total explored area: %.2lf
    
    ",++cas,s);
            //POJ上提交G++的同学请改为%.2f 
        }
        return 0;
    }
    扫描线
  • 相关阅读:
    Ubuntu配置sublime text 3的c编译环境
    ORA-01078错误举例:SID的大写和小写错误
    linux下多进程的文件拷贝与进程相关的一些基础知识
    ASM(四) 利用Method 组件动态注入方法逻辑
    基于Redis的三种分布式爬虫策略
    Go语言并发编程总结
    POJ2406 Power Strings 【KMP】
    nyoj 会场安排问题
    Server Tomcat v7.0 Server at localhost was unable to start within 45 seconds. If the server requires more time, try increasing the timeout in the server editor.
    Java的String、StringBuffer和StringBuilder的区别
  • 原文地址:https://www.cnblogs.com/gosick/p/11265295.html
Copyright © 2020-2023  润新知