hdu1542线段树(扫描线+离散化)

Posted MalcolmMeng

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了hdu1542线段树(扫描线+离散化)相关的知识,希望对你有一定的参考价值。

题目链接

要求矩形的面积并

代码不复杂,主要要理解扫描线的思想以及一些细节的处理。

首先需要将接收到的x坐标离散化,方法就是排序去重。接下来的线段树建立在这个

关于x坐标的数组上,这很关键。线段树的节点代表一段区间,这个区间是由x坐标数组的下标

来构成的。更新的时候就根据水平线段的左右x坐标获得区间,然后更新区间。

看了这么多,离散化之后关于r+1,r-1的问题还是很模糊。

我尽力理解一下,有一个[0,4]的区间,叶节点分别为[0,0],[1,1],[2,2],[3,3],[4,4],

那么[0,0]节点表示的是区间[0,1];[1,1]节点表示的区间[1,2];[2,2]节点表示的区间[2,3];[3,3]节点表示区间[3,4];

当向上传递时[0,1]节点表示区间[0,2],以此类推

#include<cstdio>
#include<algorithm>
#include<vector>
using namespace std;
const int maxn=110;//最多矩形个数
struct seg{
    double lx,rx,y;
    short f;
    seg(){}
    seg(double lx_,double rx_,double y_,short f_):lx(lx_),rx(rx_),y(y_),f(f_){}
    bool operator <(const seg &a)const 
    {
            return y<a.y;
    }
};
int sgsNum;
seg sgs[maxn*2];
int x2nNum;
//x2n
double x2n[maxn*2];
double len[maxn*8];
int num[maxn*8];
void build(int root,int l,int r)
{
    len[root]=num[root]=0;
    if(l==r)return;
    int mid=(l+r)/2;
    build(root*2,l,mid);
    build(root*2+1,mid+1,r);
}
void pushUp(int root,int l,int r)
{
    if(num[root]){
        len[root]=x2n[r+1]-x2n[l];
    }else if(l==r){
        len[root]=0;
    }
    else {
        len[root]=len[root*2]+len[root*2+1];
    }
}
void update(int root,int L,int R,int f,int l,int r)
{
    if(L<=l&&r<=R){
        num[root]+=f;
        pushUp(root,l,r);
        return;
    }
    int mid=l+(r-l)/2;
    if(L<=mid)update(root*2,L,R,f,l,mid);
    if(mid<R)update(root*2+1,L,R,f,mid+1,r);
    pushUp(root,l,r);
}
int bin(double k)
{
    int m,l=0,r=x2nNum-1;
    while(l<=r){
        m=(l+r)/2;
        if(x2n[m]==k)return m;
        else if(x2n[m]>k)r=m-1;
        else l=m+1;
    }
    return -1;
}
int main()
{
    //freopen("in.txt","r",stdin);
    int n,p=0;
    while(scanf("%d",&n)!=EOF&&n!=0){
        sgsNum=0,x2nNum=0;
        p++;
        for(int i=0;i<n;i++){
            double lx,ly,rx,ry;
            scanf("%lf%lf%lf%lf",&lx,&ly,&rx,&ry);
            sgs[sgsNum++]=seg(lx,rx,ly,1);
            sgs[sgsNum++]=seg(lx,rx,ry,-1);
            x2n[x2nNum++]=lx;
            x2n[x2nNum++]=rx;
        }
        double area=0;
        sort(x2n,x2n+x2nNum);
        sort(sgs,sgs+sgsNum);
        x2nNum=unique(x2n,x2n+x2nNum)-x2n;
        build(1,0,x2nNum-1);
        for(int i=0;i<sgsNum-1;i++){
            int l=bin(sgs[i].lx);
            int r=bin(sgs[i].rx)-1;
            update(1,l,r,sgs[i].f,0,x2nNum-1);
            area+=len[1]*(sgs[i+1].y-sgs[i].y);
        }
        printf("Test case #%d\\n",p);
        printf("Total explored area: %.2lf\\n\\n",area);
    }
    //while(1);
}

参考资料

http://www.cnblogs.com/zhangmingcheng/p/3907072.html

http://blog.csdn.net/qq_37497322/article/details/75126251

以上是关于hdu1542线段树(扫描线+离散化)的主要内容,如果未能解决你的问题,请参考以下文章

hdu1542 Atlantis (线段树+扫描线+离散化)

HDU - 1542 扫描线入门+线段树离散化

HDU1542-Atlantis离散化&线段树&扫描线个人认为很全面的详解

扫描线,线段树,离散化——HDU - 1542

HDU 1542.Atlantis-线段树求矩形面积并(离散化扫描线/线段树)-贴模板

HDU 1542 Atlantis(线段树扫描线+离散化求面积的并)