POJ 1151(线段树+扫描线)

这篇博客介绍了一种利用线段树处理扫描线算法的方法,主要针对坐标中平行于x、y轴的矩形覆盖面积计算。通过离散化x坐标,建立并用线段树维护区间,在每条扫描线进行区间覆盖更新,以此计算面积。文章以一个包含4条扫描线和3个区间的例子详细说明了这个过程,并提供了相应的代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

CF上遇到一题扫描线,二话不说立刻补。

该类题目计算坐标中边平行于x,y轴的矩形的覆盖面积。

这样可以通过离散化x坐标,然后建立区间,通过线段树管理。

然后每条扫描线更新区间覆盖和计算面积。


                                                                                

对于上面的矩形就有4条扫描线,有3个区间。

第一条扫描线覆盖1,2区间。

第二条扫描线覆盖2,3区间。

第三条扫描线是第一个矩阵的下边,所以取消1,2区间的覆盖,但因为区间2还有第二条扫描线仍然覆盖区间2,故总覆盖依然是2,3区间。

如何判断区间是否被覆盖,可以通过区别矩阵上下边来达成,上边cover值为1,下边cover值为-1,则被覆盖的区间覆盖值不为0。


代码如下:

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <iostream>

using namespace std;

#define lson(i) i*2
#define rson(i) i*2+1

const int maxn=4222;

struct Node
{
    double x1,x2,y;
    int c;
    Node(){}
    Node(double x1,double x2,double y,int c):x1(x1),x2(x2),y(y),c(c){}
    bool operator<(const Node& b)const
    {
        return y>b.y;
    }
}line[maxn];
double x[maxn];
int flag[maxn];
double sum[maxn];
int ql,qr;

int bfind(int l,int r,double v)
{
    int m;
    while(l<r)
    {
        m=l+(r-l)/2;
        if(x[m]<v)l=m+1;
        else r=m;
    }
    return l;
}

void pushup(int i,int l,int r)
{
    if(flag[i])sum[i]=x[r]-x[l-1];
    else if(l==r)sum[i]=0;
    else sum[i]=sum[lson(i)]+sum[rson(i)];
}

void update(int i,int l,int r,int c)
{
    if(ql<=l&&r<=qr)
    {
        flag[i]+=c;
        pushup(i,l,r);
    }
    else
    {
        int m=l+(r-l)/2;
        if(ql<=m)update(lson(i),l,m,c);
        if(m<qr)update(rson(i),m+1,r,c);
        pushup(i,l,r);
    }
}

int main()
{
    //freopen("in.txt","r",stdin);
    int n,t=0;
    double x1,x2,y1,y2;
    int cot;
    while(scanf("%d",&n)==1&&n)
    {
        memset(sum,0,sizeof(sum));
        memset(flag,0,sizeof(flag));
        cot=0;
        for(int i=0;i<n;i++)
        {
            //cin>>x1>>y1>>x2>>y2;
            scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
            line[cot]=Node(x1,x2,y1,1);
            x[cot++]=x1;
            line[cot]=Node(x1,x2,y2,-1);
            x[cot++]=x2;
        }
        sort(x,x+cot);
        sort(line,line+cot);
        int k=0;
        double ans=0;
        for(int i=1;i<cot;i++)
            if(x[i]!=x[i-1])x[++k]=x[i];
        for(int i=0;i<cot-1;i++)
        {
            ql=bfind(0,k,line[i].x1)+1;
            qr=bfind(0,k,line[i].x2);
            update(1,1,k,line[i].c);
            ans+=sum[1]*(line[i].y-line[i+1].y);
        }
        printf("Test case #%d\n",++t);
        printf("Total explored area: %.2lf\n\n",ans);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值