CodeVS3044 矩形面积求并

该博客介绍了如何利用扫描线线段树解决在100000×100000坐标上的矩形面积求并问题。通过对x坐标离散化,使用线段树维护每个矩形的边界,按y坐标顺序处理,计算出所有矩形并集的面积。博客中提到,线段树维护的是x轴上的边,而非孤立的点,并解释了为何此线段树不需要pushdown操作。

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

http://codevs.cn/problem/3044/
题意:在 100000 ∗ 100000 100000*100000 100000100000的坐标上输入n个矩形,边长为实数,求这些矩形的并的面积。
思路:扫描线线段树,黄学长讲的非常好:http://hzwer.com/879.html
大致记录一下:对所有x坐标离散化,对x坐标建一颗线段树,在下边界加入,上边界删去。按照y坐标从小到大的顺序,依次处理所有相邻y坐标夹的子矩形,矩形的高就是 y 1 − y 2 y_1-y_2 y1y2,长是所有被覆盖的x的段。注意线段树维护的是x轴上的边,而不是孤立的点。举个例子,x坐标是1,2,3,4,现在[1,3]增加,划分为[1,2]和[3,3],如果维护点,就只有 1 − 2 1-2 12,而没有 2 − 3 2-3 23,规定边i连接点i和i+1,应该[1,3]增加变成边[1,2]增加,线段树maintain里边也要做修改。
还有要注意这个线段树不需要pushdown的原因是:一段+1后,即使它的子段-1,这段一定还都被覆盖,因为还没到这个大段-1的时候。
盗一张图(来自https://www.cnblogs.com/milky-w/p/8426772.html
在这里插入图片描述

#include<bits/stdc++.h>
using namespace std;
#define maxn (100000+100)

int n;
double hash[maxn*2];
struct Query{
    double x1,x2,y;
    int flag;
    bool operator < (Query x)const{
        return y<x.y;
    }
}Q[maxn*2];
int ql,qr,val,col[maxn*8];
double sumv[maxn*8];
double ans;

void maintain(int o,int l,int r)
{
    if(col[o])sumv[o]=hash[r+1]-hash[l];
    else if(l==r)sumv[o]=0;
    else sumv[o]=sumv[o*2]+sumv[o*2+1];
}

void update(int o,int l,int r)
{
    if(ql<=l&&qr>=r)col[o]+=val;
    else
    {
        int mid=(l+r)/2;
        if(ql<=mid)update(o*2,l,mid);
        if(qr>mid)update(o*2+1,mid+1,r);
    }
    maintain(o,l,r);
}

int main()
{
    //freopen("input.in","r",stdin);
    while(cin>>n && n)
    {
        ans=0;
        memset(sumv,0,sizeof(sumv));
        memset(col,0,sizeof(col));
        double x1,x2,y1,y2;
        for(int i=1;i<=n;i++)
        {
            scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
            Q[i*2-1].x1=Q[i*2].x1=x1;
            Q[i*2-1].x2=Q[i*2].x2=x2;
            Q[i*2-1].y=y1;Q[i*2-1].flag=1;
            Q[i*2].y=y2;Q[i*2].flag=-1;
            hash[i*2-1]=x1;hash[i*2]=x2;
        }
        sort(Q+1,Q+1+2*n);sort(hash+1,hash+1+2*n);
        for(int i=1;i<=2*n;i++)
        {
            ql=lower_bound(hash+1,hash+2*n+1,Q[i].x1)-hash;
            qr=lower_bound(hash+1,hash+2*n+1,Q[i].x2)-hash-1;
            val=Q[i].flag;
            update(1,1,2*n);
            ans+=sumv[1]*(Q[i+1].y-Q[i].y);
        }
        printf("%.2f\n",ans);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值