zoukankan      html  css  js  c++  java
  • [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;
    }
    扫描线
  • 相关阅读:
    scrapy中selenium的应用
    Django的锁和事务
    redis
    【leetcode】187. Repeated DNA Sequences
    【leetcode】688. Knight Probability in Chessboard
    【leetcode】576. Out of Boundary Paths
    【leetcode】947. Most Stones Removed with Same Row or Column
    【leetcode】948. Bag of Tokens
    【leetcode】946. Validate Stack Sequences
    【leetcode】945. Minimum Increment to Make Array Unique
  • 原文地址:https://www.cnblogs.com/gosick/p/11265295.html
Copyright © 2011-2022 走看看