计算几何-扫描线

今日正题基础应用一面积并

存在这样两个矩形求其面积并。

  

第一步:我们将所有矩形的横边都画上线,我们的扫描线就从下往上扫 (扫描线一般是从下往少,或者从左往右,当然你学会了也可以有所创新)

思考🤔:这样看的话我们的扫描线扫到①边长度就为截取边的长度就好了,③边就应该是矩形2的横边长。②边怎么办?这就涉及到标记了!

第二步 :每一个矩形的下边权值为1(代表入边),上边权值为-1(出边),结合线段树维护区间,当扫到①时a[1]到a[3]这一段长度更新,扫描线长度a[3]-a[1],当扫到②边a[2]到a[4]更新,a[2]到a[3]标记累计,扫描线长度a[4]-a[1]。当扫到③边a[1]到a[3]更新,扫描线长度a[4]-a[2],有一个发现a[2]到a[3]总共被累计两次,所以即便③边出边了一段a[2]到a[3]但是扫描线的长度还是有这段距离的。基本思路就到这里代码详解。

#include<bits/stdc++.h>
#define put putchar
#define get getchar
#define is isdigit
#define il inline
#define dfor(i,a,b) for(int i=a;i<=b;++i)
#define ls (i<<1)
#define lr (i<<1|1)
using namespace std;
typedef long long ll;
const int N=1e6+10;
int n,a[N];
struct p 
{
    int l,r,h,flag;
    p(){}
    p(int l1,int r1,int h1,int f1)
    {
        l=l1,r=r1,h=h1,flag=f1;
    }
}node[N<<1];//用一个结构体来储存横边的信息,横边的左右横坐标,纵坐标和权值
//当我们的扫描线扫到当前横边时就用上面一条横边的纵坐标减去当前横边的纵坐标乘以扫描线截取的长度
//所以我们的node结构体应该从小到大排序根据纵坐标的值
struct p1
{
    int l,r,sum,len;
    p1(){}
    p1(int l1,int rr,int ss,int ee)
    {
        l=l1,r=rr,sum=ss,len=ee;
    }
}tr[N<<2];//这就是我们的线段树了,l,r维护区间的基本操作了,sum就是用来累计标记的,len就是我们
//扫描线截取的长度
bool cmp(p a,p b)
{
    return a.h<b.h;
}//node结构体排序
void build(int i,int l,int r)
{
    tr[i]=p1(l,r,0,0);
    if(l==r) return ;
    int mid=l+r>>1;
    build(ls,l,mid);
    build(lr,mid+1,r);
}//建树基操
il void push(int i)
{
    if(tr[i].sum) tr[i].len=a[tr[i].r+1]-a[tr[i].l];
    else tr[i].len=tr[ls].len+tr[lr].len;
}//当一个区间被标记完全说明当前区间完全处于扫描线正在扫描的横边内,直接区间横坐标之差计算了
//没有被标记,当前区间的len就为左右儿子的len之和
void modify(int i,int L,int R,int k)
{
    if(L<=a[tr[i].l]&&a[tr[i].r+1]<=R)//下面详解
    {
        tr[i].sum+=k;
        push(i);
        return ;
    }
    if(L<=a[tr[ls].r]) modify(ls,L,R,k);
    if(R>a[tr[lr].l]) modify(lr,L,R,k);//R>=a[tr[lr].l+1]==R>a[tr[lr].l]
    push(i);
}

当前扫描线扫瞄到的横边为横坐标分别为(1,8) ,所以呢?更新线段树的条件还是原来的左右端点分别对应吗?答案是:否!可以发现线段树某一个区间(l,r)对应上坐标系的区间维护的其实是(l,r+1),所以?当我们抛出一个坐标系区间去更新线段树时,线段树的右端点应该加上1去对应坐标系区间!!!正解 下面完整代码👇

#include<bits/stdc++.h>
#define put putchar
#define get getchar
#define is isdigit
#define il inline
#define dfor(i,a,b) for(int i=a;i<=b;++i)
#define ls (i<<1)
#define lr (i<<1|1)
using namespace std;
typedef long long ll;
const int N=1e6+10;
int n,a[N];
struct p 
{
    int l,r,h,flag;
    p(){}
    p(int l1,int r1,int h1,int f1)
    {
        l=l1,r=r1,h=h1,flag=f1;
    }
}node[N<<1];
struct p1
{
    int l,r,sum,len;
    p1(){}
    p1(int l1,int rr,int ss,int ee)
    {
        l=l1,r=rr,sum=ss,len=ee;
    }
}tr[N<<2];
bool cmp(p a,p b)
{
    return a.h<b.h;
}
void build(int i,int l,int r)
{
    tr[i]=p1(l,r,0,0);
    if(l==r) return ;
    int mid=l+r>>1;
    build(ls,l,mid);
    build(lr,mid+1,r);
}
il void push(int i)
{
    if(tr[i].sum) tr[i].len=a[tr[i].r+1]-a[tr[i].l];
    else tr[i].len=tr[ls].len+tr[lr].len;
}
void modify(int i,int L,int R,int k)
{
    if(L<=a[tr[i].l]&&a[tr[i].r+1]<=R)
    {
        tr[i].sum+=k;
        push(i);
        return ;
    }
    if(L<=a[tr[ls].r]) modify(ls,L,R,k);
    if(R>a[tr[lr].l]) modify(lr,L,R,k);
    push(i);
}
int main()
{
    cin>>n;
    int x,xx,y,yy;
    for(int i=1;i<=n;++i)
    {
        cin>>x>>y>>xx>>yy;
        a[ls]=x,a[lr-2]=xx;//a数组记录横坐标主要用于离散化,因为数据范围开不了那么大数组
//ls==(i<<1)==i*2,lr==(i<<1|1)==i*2+1,一条线段两个横坐标
        node[ls]=p(x,xx,y,1),node[lr-2]=p(x,xx,yy,-1);//node结构体记录每条横边信息
    }
    n<<=1;//上面记录的都是两倍的信息了,直接放大方便些
    sort(a+1,a+n+1);
    sort(node+1,node+n+1,cmp);
    int tot=unique(a+1,a+n+1)-a-1;//不去重区间的对应关系会出错
//试想1 2 3 3 3 4 我们要更新1-4,本应该4和4比,但是数组4的位置时3,这不就错了吗
//有的是用二分查找,你查找4的位置不去重找出来的是6,这不也错了吗
    build(1,1,tot-1);//为什么tot-1?还是更新1-4,我建树1-3,我更新时是不是右端点要+1
//并且我们的比较还是R和a[tr[i].r+1]的比较,3+1等于4,R和a[4]比较
    ll ans=0;
    for(int i=1;i<n;++i)//最后一条边不用管了我们用的上面一条边的纵坐标减去下面一条边的纵坐标
//你假设只有一个矩形就懂了
    {
        modify(1,node[i].l,node[i].r,node[i].flag);//1是基操,l,r对应区间,flag我们的标记
        ans+=tr[1].len*(ll)(node[i+1].h-node[i].h);//底乘高这。。。
    }
    cout<<ans;
    return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
计算几何算法(含源代码) ㈠ 点的基本运算 1. 平面上两点之间距离 1 2. 判断两点是否重合 1 3. 矢量叉乘 1 4. 矢量点乘 2 5. 判断点是否在线段上 2 6. 求一点饶某点旋转后的坐标 2 7. 求矢量夹角 2 ㈡ 线段及直线的基本运算 1. 点与线段的关系 3 2. 求点到线段所在直线垂线的垂足 4 3. 点到线段的最近点 4 4. 点到线段所在直线的距离 4 5. 点到折线集的最近距离 4 6. 判断圆是否在多边形内 5 7. 求矢量夹角余弦 5 8. 求线段之间的夹角 5 9. 判断线段是否相交 6 10.判断线段是否相交但不交在端点处 6 11.求线段所在直线的方程 6 12.求直线的斜率 7 13.求直线的倾斜角 7 14.求点关于某直线的对称点 7 15.判断两条直线是否相交及求直线交点 7 16.判断线段是否相交,如果相交返回交点 7 ㈢ 多边形常用算法模块 1. 判断多边形是否简单多边形 8 2. 检查多边形顶点的凸凹性 9 3. 判断多边形是否凸多边形 9 4. 求多边形面积 9 5. 判断多边形顶点的排列方向,方法一 10 6. 判断多边形顶点的排列方向,方法二 10 7. 射线法判断点是否在多边形内 10 8. 判断点是否在凸多边形内 11 9. 寻找点集的graham算法 12 10.寻找点集凸包的卷包裹法 13 11.判断线段是否在多边形内 14 12.求简单多边形的重心 15 13.求凸多边形的重心 17 14.求肯定在给定多边形内的一个点 17 15.求从多边形外一点出发到该多边形的切线 18 16.判断多边形的核是否存在 19 ㈣ 圆的基本运算 1 .点是否在圆内 20 2 .求不共线的三点所确定的圆 21 ㈤ 矩形的基本运算 1.已知矩形三点坐标,求第4点坐标 22 ㈥ 常用算法的描述 22 ㈦ 补充 1.两圆关系: 24 2.判断圆是否在矩形内: 24 3.点到平面的距离: 25 4.点是否在直线同侧: 25 5.镜面反射线: 25 6.矩形包含: 26 7.两圆交点: 27 8.两圆公共面积: 28 9. 圆和直线关系: 29 10. 内切圆: 30 11. 求切点: 31 12. 线段的左右旋: 31 13.公式: 32

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Heredy

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值