• POJ-1151-Atlantis(线段树+扫描线+离散化)[矩形面积并]


    题意:求矩形面积并

    分析:使用线段树+扫描线...因为坐标是浮点数的,因此还需要离散化!

    把矩形分成两条边,上边和下边,对横轴建树,然后从下到上扫描上去,用col表示该区间有多少个下边,sum代表该区间内被覆盖的线段的长度总和

    这里线段树的一个结点并非是线段的一个端点,而是该端点和下一个端点间的线段,所以题目中r+1,r-1的地方可以自己好好的琢磨一下

    详细分析下扫描线

    第一次完全看懂扫描线.

    像这题的样例:

    这么两个矩形,现在要求它的面积并.

    假设我门将横边座位扫描线,即每个矩形有两条扫描线,下扫描线,下扫描线,

    每条扫描线我们用结构体

    const int MAXN=250;
    struct seg{
        double x1,x2,y;
        int flag;
        bool operator <(const seg& rsh)const{
            return y<rsh.y;
        }
    }G[MAXN];

    来保存,保存这条扫描线的两个横坐标和一个纵坐标,还用flag标记这条扫描线是上边还是下边,下边flag=1,上边flag=-1;

    将扫描线都存好后,按照横坐标排序,使得每条边从下到上的顺序(a1,a2,a3,a4)

    现在可以边看程序边看这..

    将a1插入线段树后计算a1覆盖的总长度sum[1]

    则红色部分的面积就可以算出来了,sum[1]*(G[i+1].y-G[i].y)

    将a2插入线段树中,计算得到总长度为蓝色部分的底边,sum[1]

    则蓝色部分的面积也就可以算出来了sum[1]*(G[i+1].y-G[i].y)

    最后将a3插入树中,因为a3是上边,因此把红色的底边给消除了,这是线段树计算得的结果为黄色部分的底边sum[1]

    则黄色部分的面积为sum[1]*(G[i+1].y-G[i].y)

    如此,把三个部分的面积加起来就是矩形面积并了.这也就是扫描线计算计算面积并的基本过程了!

    // File Name: 1151.cpp
    // Author: Zlbing
    // Created Time: 2013/7/20 14:36:01
    
    #include<iostream>
    #include<string>
    #include<algorithm>
    #include<cstdlib>
    #include<cstdio>
    #include<set>
    #include<map>
    #include<vector>
    #include<cstring>
    #include<stack>
    #include<cmath>
    #include<queue>
    using namespace std;
    #define CL(x,v); memset(x,v,sizeof(x));
    #define INF 0x3f3f3f3f
    #define LL long long
    #define REP(i,r,n) for(int i=r;i<=n;i++)
    #define RREP(i,n,r) for(int i=n;i>=r;i--)
    
    #define lson l,m,rt<<1
    #define rson m+1,r,rt<<1|1
    
    const int MAXN=250;
    struct seg{
        double x1,x2,y;
        int flag;
        bool operator <(const seg& rsh)const{
            return y<rsh.y;
        }
    }G[MAXN];
    double hash[MAXN];
    
    double sum[MAXN<<2];
    int col[MAXN<<2];
    
    void pushup(int rt,int l,int r)
    {
        if(col[rt])
        {
            sum[rt]=hash[r+1]-hash[l];
        }
        else if(l==r)sum[rt]=0;
        else sum[rt]=sum[rt<<1]+sum[rt<<1|1];
    }
    
    void update(int L,int R,int flag,int l,int r,int rt)
    {
        if(L<=l&&R>=r)
        {
            col[rt]+=flag;
            pushup(rt,l,r);
            return;
        }
        int m=(l+r)>>1;
        if(L<=m)update(L,R,flag,lson);
        if(R>m)update(L,R,flag,rson);
        pushup(rt,l,r);
    }
    int main()
    {
        int cas=1;
        int n;
        while(~scanf("%d",&n))
        {
            if(n==0)break;
            int xlen=0;
            double a,b,c,d;
            REP(i,1,n)
            {
                scanf("%lf%lf%lf%lf",&a,&b,&c,&d);
                G[xlen].x1=a,G[xlen].x2=c,G[xlen].y=b,G[xlen].flag=1;
                hash[xlen]=a;
                xlen++;
                hash[xlen]=c;
                G[xlen].x1=a,G[xlen].x2=c,G[xlen].y=d,G[xlen].flag=-1;
                xlen++;
            }
            sort(G,G+xlen);
            sort(hash,hash+xlen);
            CL(col,0);
            CL(sum,0);
            double ans=0;
            for(int i=0;i<xlen-1;i++)
            {
                int l=lower_bound(hash,hash+xlen,G[i].x1)-hash;
                int r=lower_bound(hash,hash+xlen,G[i].x2)-hash-1;
                if(l<=r)update(l,r,G[i].flag,0,xlen-1,1);
                ans+=sum[1]*(G[i+1].y-G[i].y);
            }
            printf("Test case #%d
    ",cas++);
            printf("Total explored area: %.2lf
    
    ",ans);
        }
        return 0;
    }
  • 相关阅读:
    hadoop配置
    50070端口浏览器上删除dfs的文件提示无权限Permission denied,解决方法
    离线ETL测试点
    hadoop集群启动命令汇总
    ETL测试类型
    ssh配置免密方法
    Redis哨兵
    如何实现两栏布局,右侧自适应?三栏布局中间自适应呢?
    Set、Map、WeakSet、WeakMap
    offsetTop和scrollTop的差别
  • 原文地址:https://www.cnblogs.com/arbitrary/p/3202630.html
Copyright © 2020-2023  润新知