线段树辅助——扫描线法计算矩形面积并

分析:

1.矩形比较多,坐标也很大,所以横坐标需要离散化(纵坐标不需要)

2.重点:扫描线法:假想有一条扫描线,从左往右(从右往左),或者从下往上(从上往下)扫描过整个多边形(或者说畸形。。多个矩形叠加后的那个图形)。如果是竖直方向上扫描,则是离散化横坐标,如果是水平方向上扫描,则是离散化纵坐标。下面的分析都是离散化横坐标的,并且从下往上扫描的。

   扫描之前还需要做一个工作,就是保存好所有矩形的上下边,并且按照它们所处的高度进行排序,另外如果是上边我们给他一个值-1,下边给他一个值1,我们用一个结构体来保存所有的上下边 

struct segment
{
double l,r,h;   //l,r表示这条上下边的左右坐标,h是这条边所处的高度
int f;   //所赋的值,1或-1
}

接着扫描线从下往上扫描,每遇到一条上下边就停下来,将这条线段投影到总区间上(总区间就是整个多边形横跨的长度),这个投影对应的其实是个插入和删除线段操作。还记得给他们赋的值1或-1吗,下边是1,扫描到下边的话相当于往总区间插入一条线段,上边-1,扫描到上边相当于在总区间删除一条线段(如果说插入删除比较抽象,那么就直白说,扫描到下边,投影到总区间,对应的那一段的值都要增1,扫描到上边对应的那一段的值都要减1,如果总区间某一段的值为0,说明其实没有线段覆盖到它,为正数则有,那会不会为负数呢?是不可能的,可以自己思考一下)。

每扫描到一条上下边后并投影到总区间后,就判断总区间现在被覆盖的总长度,然后用下一条边的高度减去当前这条边的高度,乘上总区间被覆盖的长度,就能得到一块面积,并依此做下去,就能得到最后的面积

(这个过程其实一点都不难,只是看文字较难体会,建议纸上画图,一画即可明白,下面献上一图希望有帮组)

附上代码:


#include<bits/stdc++.h>

using namespace std;

#define MAXN 50004*2

struct node{
    int l,r;            //离散化后构建线段树的左右x坐标点位置
    int cover;          //用来记录重叠情况
    double len,lf,rf;   //len计算实在的长度,rf,lf对应真实数据
}segTree[MAXN<<2];

struct Line{
    double y,x1,x2;
    int f;              //1表示入边,-1表示出边
}line[MAXN<<1];

bool cmp(Line a,Line b){
    return a.y<b.y;
}

double x[MAXN<<1];

void build(int t,int l,int r){
    segTree[t].l=l;segTree[t].r=r;
    segTree[t].len=segTree[t].cover=0;
    segTree[t].lf=x[l];
    segTree[t].rf=x[r];
    if(l+1==r){
        return;
    }
    int mid=l+r>>1;
    build(t<<1,l,mid);
    build(t<<1|1,mid,r);
}

void cal_len(int t){//计算长度
    if(segTree[t].cover>0){
        segTree[t].len=segTree[t].rf-segTree[t].lf;
        return ;
    }
    if(segTree[t].l+1==segTree[t].r){
        segTree[t].len=0;
    }else{
        segTree[t].len=segTree[t<<1].len+segTree[t<<1|1].len;
    }
}

void update(int t,Line e){   //加入线段e后更新线段树
    if(e.x1==segTree[t].lf&&e.x2==segTree[t].rf){
        segTree[t].cover+=e.f;
        cal_len(t);
        return;
    }
    if(e.x2<=segTree[t<<1].rf){
        update(t<<1,e);
    }else if(e.x1>=segTree[t<<1|1].lf){
        update(t<<1|1,e);
    }else{
        Line tmp=e;
        tmp.x2=segTree[t<<1].rf;
        update(t<<1,tmp);
        tmp=e;
        tmp.x1=segTree[t<<1|1].lf;
        update(t<<1|1,tmp);
    }
    cal_len(t);
}

int main(){
    int i,n,t;
    double x1,x2,y1,y2;
    while(scanf("%d",&n)!=EOF){
        t=1;
        for(int i=1;i<=n;i++){
            scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
            line[t].y=y1;
            line[t].x1=x1;
            line[t].x2=x2;
            line[t].f=1;
            x[t]=x1;
            t++;
            line[t].y=y2;
            line[t].x1=x1;
            line[t].x2=x2;
            line[t].f=-1;
            x[t]=x2;
            t++;
        }
        sort(line+1,line+t,cmp);
        sort(x+1,x+t);
        int len=unique(x+1,x+t)-x;
        build(1,1,len-1);
        update(1,line[1]);
        double res=0;
        for(int i=2;i<t;i++){
            res+=segTree[1].len*(line[i].y-line[i-1].y);
            update(1,line[i]);
        }
        printf("%.0f\n",res);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/zhouzi2018/article/details/80601141