训练日记-30

来源:互联网 发布:网络教育一般多少学费 编辑:程序博客网 时间:2024/05/22 23:00

        基本每周就周末时间多点,周末能多刷几道题,这两天好像刷了两道树状数组题,还有三道线段树题,这几道题大部分都是与离散化有关的,其中线段树有两道是关于扫描线的。在做这类问题之前,实现去博客看了一下扫描线的基本原理跟具体操作。

       扫描线主要用于帮助线段树来解决二维面积问题的。

      

       其具体实现的基本模版如下:

#include<cstdio>

#include<cstring>

#include<algorithm>

using namespace std;

const int MAXN=2222;

#define lson i*2,l,m

#define rson i*2+1,m+1,r

#define root 1,1,k-1

double X[MAXN];

struct node

{

    double l,r,h;

    int d;

    node(){}

    node(double a,double b,double c,int d): l(a),r(b),h(c),d(d){}

    bool operator <(const node &b)const

    {

        return h<b.h;

    }

}nodes[MAXN];

int cnt[MAXN*4];

double sum[MAXN*4];

void PushDown(int i,int l,int r)

{

    int m=(l+r)/2;

    if(cnt[i]!=-1)

    {

        cnt[i*2]=cnt[i*2+1]=cnt[i];

        sum[i*2]= (cnt[i]?(X[m+1]-X[l]):0) ;

        sum[i*2+1]= (cnt[i]?(X[r+1]-X[m+1]):0) ;

    }

}

void PushUp(int i,int l,int r)

{

    if(cnt[i*2]==-1 || cnt[i*2+1]==-1)

        cnt[i]=-1;

    else if(cnt[i*2] != cnt[i*2+1])

        cnt[i]=-1;

    else

        cnt[i]=cnt[i*2];

    sum[i]=sum[i*2]+sum[i*2+1];

}

void build(int i,int l,int r)

{

    if(l==r)

    {

        cnt[i]=0;

        sum[i]=0.0;

        return ;

    }

    int m=(l+r)/2;

    build(lson);

    build(rson);

    PushUp(i,l,r);

}

void update(int ql,int qr,int v,int i,int l,int r)

{

    if(ql<=l && r<=qr)

    {

        if(cnt[i]!=-1)

        {

            cnt[i]+=v;

            sum[i] = (cnt[i]? (X[r+1]-X[l]):0);

            return ;

        }

    }

    PushDown(i,l,r);

    int m=(l+r)/2;

    if(ql<=m) update(ql,qr,v,lson);

    if(m<qr) update(ql,qr,v,rson);

    PushUp(i,l,r);

}

int bin(double key,int n,double d[])

{

    int l=1,r=n;

    while(r>=l)

    {

        int m=(r+l)/2;

        if(d[m]==key)

            return m;

        else if(d[m]>key)

            r=m-1;

        else

            l=m+1;

    }

    return -1;

}

int main()

{

    int q;

    int kase=0;

    while(scanf("%d",&q)==1&&q)

    {

        int n=0,m=0;

        for(int i=1;i<=q;i++)

        {

            double x1,y1,x2,y2;

            scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);

            X[++n]=x1;

            nodes[++m]=node(x1,x2,y1,1);

            X[++n]=x2;

            nodes[++m]=node(x1,x2,y2,-1);

        }

        sort(X+1,X+n+1);

        sort(nodes+1,nodes+m+1);

        int k=1;//共k个不同的x坐标,组成了k-1个不同的区域

        for(int i=2;i<=n;i++)

            if(X[i]!=X[i-1]) X[++k]=X[i];

        build(1,1,k-1);//少了build就WA

        double ret=0.0;//最终面积

        for(int i=1;i<m;i++)

        {

            int l=bin(nodes[i].l,k,X);

            int r=bin(nodes[i].r,k,X)-1;

            if(l<=r) update(l,r,nodes[i].d,root);

            ret += sum[1]*(nodes[i+1].h-nodes[i].h);

        }

        printf("Test case #%d\nTotal explored area: %.2lf\n\n",++kase,ret );

    }

}



   摘自:http://blog.csdn.net/u013480600/article/details/22548393

这篇博客介绍的扫描线挺详细的,而且解释俗通俗易懂,如果想了解扫描线,极力推荐!


长路漫漫,还需继续努力!



原创粉丝点击