现在的位置: 首页 > 综合 > 正文

poj 1151 Atlantis(线段树+扫描线)

2013年10月23日 ⁄ 综合 ⁄ 共 2092字 ⁄ 字号 评论关闭

题意:求给出的n个矩形的面积并


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


思路:

终于接触扫描线了,nice~~~

1.由于坐标是浮点数,离散化(如果数据范围很大或者浮点数,离散化 ^_^)

2.如何扫着过去,求出面积呢?

看下面的图:


(直接借用的~~)


每个矩形直接转换为两条线,这两条线分别是上边和下边,对应的y1,此时对应的横坐标区间[x1,x2] 和 y2对应的横坐标区间也是[x1,x2],

同时那些线也就是y从哪里来的呢,是那些矩形的y坐标排序,这样子扫过去,只要确定了每两条线之间的宽度,那么相邻两条线的高度差*宽度也就是一个小矩形的面积了,所有的加起来也就是并的和了,

从y扫过去的时候,首先将一条边插入线段树,然后得到当前当前扫描线所在位置的覆盖到的边的总长,

第一次插入A1B1,扫描线覆盖的边长就是A1B1,再用它直接乘高度就是第一个小矩形的面积;

第二次插入的时候,扫描覆盖的边长就是A2B2,同理可得到第二个矩形的面积;

第三次插入的时候,由于已经到达第一个矩形的上边,无法进行计算,(如何判断是不是上边呢,就需要一个标记,-1)那么此时覆盖的边长也就是A3B3了,同理可得到第二个矩形的面积;

三者相加就是总面积了

注意的一点:

插入的时候也得注意,不是根据坐标计算出其离散值就当做区间直接插入,而是要将右坐标的离散值减1,这个线段树中,每个点代表一个区间



#include <iostream>
#include <stdio.h>
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
#define maxn 1000
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1

struct LINE{
    double y,x_left,x_right;
    int flag;
    LINE(){}
    LINE(double _y,double _x_left,double _x_right,int _f):y(_y),x_left(_x_left),x_right(_x_right),flag(_f){}
}line[maxn<<2];


int cover[maxn<<2];
double sum[maxn<<2];

double X[maxn<<2];
double x1,y1,x2,y2;

int n,t;

bool cmp(double a,double b){
    if(a < b) return true;
    return false;
}

bool cmp1(LINE a,LINE b){
    if(a.y < b.y) return true;
    return false;
}

int erfen(double res){
    int left = 0 , right = t - 1, mid;

    while(left <= right){
        mid = (left + right )/2;
        if(X[mid] == res) return mid + 1;
        else if(X[mid] < res) left = mid + 1;
        else right = mid - 1;
    }
    return -1;
}

void PushUp(int l,int r,int rt){
    if(cover[rt])
        sum[rt] = X[r] - X[l - 1];
    else if(l == r) sum[rt] = 0;
    else sum[rt] =sum[rt<<1]+ sum[rt<<1|1];
}

void update(int L,int R,int c,int l,int r,int rt){
    if(L <= l && r <= R){
        cover[rt] += c;
        PushUp(l,r,rt);
        return ;
    }
    int m = (l + r)/2;
    if(L <= m) update(L,R,c,lson);
    if(m <  R) update(L,R,c,rson);
    PushUp(l,r,rt);
}
int main()
{
    int ncase = 1;
    while(~scanf("%d",&n) && n){
        t = 0;
        for(int i=0;i<n;i++){
            scanf("%lf %lf %lf %lf",&x1,&y1,&x2,&y2);
            line[t] = LINE(y1,x1,x2,1);
            X[t++] = x1;
            line[t] = LINE(y2,x1,x2,-1);
            X[t++] = x2;
        }

        sort(X,X+t,cmp);
        sort(line,line+t,cmp1);

        memset(sum,0,sizeof(sum));
        memset(cover,0,sizeof(cover));

        double ans = 0;
        for(int i = 0 ;i < t - 1;i++){
            int l = erfen(line[i].x_left) ;
            int r = erfen(line[i].x_right) - 1 ;
            update(l , r ,line[i].flag , 1 , t , 1);
            ans += (line[i + 1].y - line[i].y) * sum[1];

        }

        printf("Test case #%d\n",ncase++);
        printf("Total explored area: %.2lf\n\n",ans);
    }
    return 0;
}

抱歉!评论已关闭.