POJ-1151-Atlantis-求矩形面积并(线段树+扫描线)

该博客介绍了如何利用线段树和扫描线算法解决POJ-1151 Atlantis问题,即给定多个矩形,求它们的面积并。文章通过离散化坐标、构建线段树并进行区间更新,逐步计算总面积,并提供了完整的C++代码实现。
摘要由CSDN通过智能技术生成
http://poj.org/problem?id=1151

给你n个矩形,求面积并,点范围大,需要离散化

按照套路,先离散化,然后从下往上扫描,每次更新线段树区间,累加面积和。

需要注意的就是,这里的线段树存的不是 整点,而是一段线段
如  1-2-3-4-5
 tree[1]存的是点1到点2之间的线段,
其长度为 tree[1+1]-tree[1];
 
#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <algorithm>
#include <iostream>
#include <queue>
#include <map>
#include <set>
#include <vector>
using namespace std;

const int N = 405  ;
struct node
{
    int flag;
    double lx,rx,y;
    node(){}
    node(double a,double b,double c,int d)
    {
        lx=a,rx=b,y=c,flag=d;
    }
    bool operator<(node b)const
    {
        return y<b.y;
    }
};
node line[N];
double X[N];
double  sum[4*N];
int  add[4*N];
void pushup(int i,int l,int r)
{
    if (add[i]) sum[i]=X[r+1]-X[l];     //如果整个区间被覆盖,则有效长度为整区间
    else if (l==r) sum[i]=0;                //如果是add[i]==0且是末区间,则有效长度为0
    else sum[i]=sum[i<<1]+sum[i<<1|1];      //否则如果add[i]=0,但不是末区间,则有子区间更新
}
void update(int i, int l, int r, int ql, int qr, int val) //更新区间为qlqr,当前区间为l,r,代表当前区间和的节点为i,更新值为val,
{
    if(l > qr || ql > r)        //更新区间不在当前区间内
        return ;
    if(ql<=l&&qr>=r)    //要更新的区间把当前区间完全包括,则把当前整个区间+val,然后返回上一层
    {
        add[i] += val;
       pushup(i,l,r);
        return ;
    }         //如果上面没reutrn 表示要往左右儿子区间查询,所以把延迟标记放下去
    int mid = (l + r) >> 1;
    update(i << 1, l, mid, ql, qr, val);
    update(i << 1 | 1, mid + 1, r, ql, qr, val);
       pushup(i,l,r);
}
int main()
{
    int n ,a,b,i;
    int cnt=1;
	 while(scanf("%d",&n)&&n)
     {
         memset(add,0,sizeof add);
         memset(sum,0,sizeof sum);
             double x1,x2,y1,y2;
             int num=0;
         for (int i=0;i<n;i++)
         {
             scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
             line[++num]=node(x1,x2,y1,1);
             X[num]=x1;              
             line[++num]=node(x1,x2,y2,-1);
               X[num]=x2;
         }
         sort(line+1,line+1+num);       //排序线段
         sort(X+1,X+1+num);         //离散化数组
         int num_x=unique(X+1,X+1+num)-X-1;     //去重
         double ans=0;
         for (int i=1;i<num;i++)
         {
             int l=lower_bound(X+1,X+1+num_x,line[i].lx)-X;
             int r=lower_bound(X+1,X+1+num_x,line[i].rx)-X-1;   //线段树每个端点的意义是一段线段而不是点,
            update(1,1,num_x,l,r,line[i].flag);             //更新扫描线
            ans+=sum[1]*(line[i+1].y-line[i].y);        //累加答案
         }
         printf("Test case #%d\n",cnt++);
         printf("Total explored area: %.2lf\n\n",ans);
     }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值