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

来源:互联网 发布:javascript dom是什么 编辑:程序博客网 时间:2024/05/17 21:59

题目链接:http://poj.org/problem?id=1151


题目大意:给你一些矩形,其顶点坐标是浮点数,可能相互重叠,问这些矩形覆盖到的面积是多少。


分析:我们将Y轴进行离散化,n个矩形的2n条边界,最多可将Y轴分成2n-1个区域,我们对这些区间进行编号,建立线段树。

const int M=210;struct segment{    int l,r;    double len; //表示区间上有多长的部分是落在矩形中的    int cov; //该区间当前被多少个矩形完全包含    int mid()    {        return (l+r)>>1;    }}tree[M<<2];


将矩形的纵边从左到右排序,然后依次将这些纵边插入线段树,要记住哪些纵边是矩形的左边界(始边),哪些是右边界(终边),以便插入时,对len和cov做不同的修改。插入一条边后,就根据根结点的len值增加总覆盖面积area的值:area+=len*(该边到下一条边的距离)。


实现代码如下:

#include <cstdio>#include <algorithm>#include <iostream>using namespace std;const int M=210;struct segment{    int l,r;    double len; //表示区间上有多长的部分是落在矩形中的    int cov; //该区间当前被多少个矩形完全包含    int mid()    {        return (l+r)>>1;    }}tree[M<<2];struct Line{    double x,y1,y2;    bool bleft; //标记该线段是否为矩形的左边    bool operator <(const Line &a) const    {        return x<a.x;    }}line[M];double y[M]; //记录所有矩形的y坐标void build(int rt,int l,int r){    tree[rt].l=l;    tree[rt].r=r;    tree[rt].len=0;    tree[rt].cov=0;    if(l==r) return ;    int m=tree[rt].mid();    build(rt<<1,l,m);    build(rt<<1|1,m+1,r);}void update(int rt,int l,int r,bool op){    if(tree[rt].l==l&&tree[rt].r==r)    {        if(op)         {//当前边是矩形的左边界的话,在该区间插入矩形左边的一部分或者全部,覆盖区间[l,r]            tree[rt].len=y[r+1]-y[l];            tree[rt].cov++;        }        else        {            tree[rt].cov--;            if(tree[rt].cov==0)            {                if(tree[rt].l==tree[rt].r) tree[rt].len=0;                else tree[rt].len=tree[rt<<1].len+tree[rt<<1|1].len;            }        }        return ;    }    int m=tree[rt].mid();    if(r<=m) update(rt<<1,l,r,op);    else if(l>m) update(rt<<1|1,l,r,op);    else    {        update(rt<<1,l,m,op);        update(rt<<1|1,m+1,r,op);    }    if(tree[rt].cov==0) //如果不为0,说明该区间当前仍然被某个矩形完全包含,此时不更新len值      tree[rt].len=tree[rt<<1].len+tree[rt<<1|1].len;}int main(){    int n,T=1;    while(scanf("%d",&n)&&n)    {        int yc=0,lc=0; //y[]和line[]的计数器        for(int i=0;i<n;i++)        {            double x1,y1,x2,y2;            scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);            y[yc++]=y1; y[yc++]=y2;            line[lc].x=x1;            line[lc].y1=y1;            line[lc].y2=y2;            line[lc].bleft=true;            lc++;            line[lc].x=x2;            line[lc].y1=y1;            line[lc].y2=y2;            line[lc].bleft=false;            lc++;        }        sort(y,y+yc);        yc=unique(y,y+yc)-y; //排序并去重        build(1,0,yc);         sort(line,line+lc);        double area=0;        for(int i=0;i<lc-1;i++) //插入每条边        {            int l=lower_bound(y,y+yc,line[i].y1)-y; //二分找出当前边离散化后对应的线段树的区间端点            int r=lower_bound(y,y+yc,line[i].y2)-y;            update(1,l,r-1,line[i].bleft);            area+=tree[1].len*(line[i+1].x-line[i].x);        }        printf("Test case #%d\nTotal explored area: %.2f\n\n",T++,area);    }    return 0;}


0 0
原创粉丝点击