首页 > 其他分享 >扫描线总结

扫描线总结

时间:2024-08-28 21:37:13浏览次数:7  
标签:总结 node cnt return int bi xx 扫描线

引入

面积并(周长并)
如下图给你一堆矩形求它的面积并或周长并。
image
显然直接做,就是考虑容斥,但明显不好做。
那就思考如何切割或补,显然补完要减的图形也不规整,只能考虑割。
如何将其割成规整的图形,明显矩形最容易计算和割。
把它割成矩形后发现,每次遇到某个矩形的边就会变,所以考虑一条线从下向上扫,每遇到一个与扫描线平行的边就计算一次答案。
面积并答案为线上被覆盖的长度乘与上一条边的距离。
周长并答案分俩个部分,平行的就是线上被覆盖的长度,垂直的就是线上有多少个端点(在线段内的不算)乘与上一条边的距离。
如何快速维护线上的覆盖长度和有多少段点,显然一个区间修改问题,用线段树。

代码实现

周长并

#include <bits/stdc++.h>
using namespace std;
const int N=5e4+10;
int n,ans,cnt,mx=-100010,mi=100010,las=0;
struct node
{
    int h,x,y,w;
}bi[N*2];
bool cmp(node x,node y)
{
    if(x.h==y.h)
        return x.w>y.w;//先加后减,不让会错
/*
2
0 0 4 4
0 4 4 8
*/

    return x.h<y.h;
}
struct stu
{
    int sum;//整个区间被整体覆盖了几次(类似lazytag,但不下传)
    int num;//整个区间被几条互不相交的线段覆盖
    int len;//整个区间被覆盖的总长度
    bool lflag,rflag;
}sh[N*4];
void pushup(int x,int l,int r)
{
    if(sh[x].sum)
    {
        sh[x].num=1;
        sh[x].len=r-l+1;
        sh[x].lflag=sh[x].rflag=1;
    }
    else if(l==r)
    {
        sh[x].num=0;
        sh[x].len=0;
        sh[x].lflag=sh[x].rflag=0;
    }
    else 
    {
        sh[x].num=sh[x<<1].num+sh[x<<1|1].num;
        if(sh[x<<1].rflag&&sh[x<<1|1].lflag)sh[x].num--;
        sh[x].len=sh[x<<1].len+sh[x<<1|1].len;
        sh[x].lflag=sh[x<<1].lflag;
        sh[x].rflag=sh[x<<1|1].rflag;
    }
}
void modify(int x,int l,int r,int lt,int rt,int w)
{
    if(lt<=l&&rt>=r)
    {
        sh[x].sum+=w;
        pushup(x,l,r);
        return ;
    }
    int mid=(l+r)>>1;
    if(lt<=mid)modify(x<<1,l,mid,lt,rt,w);
    if(rt>mid)modify(x<<1|1,mid+1,r,lt,rt,w);
    pushup(x,l,r);
    return;
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        int x1,y1,x2,y2;scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
        bi[++cnt].h=y1,bi[cnt].w=1,bi[cnt].x=x1,bi[cnt].y=x2;
        bi[++cnt].h=y2,bi[cnt].w=-1,bi[cnt].x=x1,bi[cnt].y=x2;
        mx=max(mx,x2);
        mi=min(mi,x1);
    }
    if(mi<0)
    {
        for(int i=1;i<=cnt;i++)
        {
            bi[i].x+=-mi+1;
            bi[i].y+=-mi+1;//加一与mx相匹配
        }
        mx-=mi;
    }
    sort(bi+1,bi+cnt+1,cmp);
    for(int i=1;i<=cnt;i++)
    {
        modify(1,mi,mx,bi[i].x,bi[i].y-1,bi[i].w);//减一是因为这是长度为1的叶子的右端点,叶子的编号是左端点即右端点-1.
        while(bi[i+1].h==bi[i].h&&bi[i+1].w==bi[i].w)
        {
            i++;
            modify(1,mi,mx,bi[i].x,bi[i].y-1,bi[i].w);
        }//同一类型一起处理
        ans+=abs(sh[1].len-las);//覆盖长度的变化
        las=sh[1].len;
        ans+=sh[1].num*2*(bi[i+1].h-bi[i].h);//垂直的边的长度
    }
    printf("%d",ans);
    return 0;
}

面积并

#include <bits/stdc++.h>
using namespace std;
const int N=5e5+10;
#define int long long
int n,ans,xx[N],cnt,mx=1e9+7,mi=0,las=0;
struct node
{
    int h,x,y,w;
}bi[N*2];
bool cmp(node x,node y)
{
    return x.h<y.h;
}
struct stu
{
    int sum;//整个区间被整体覆盖了几次(类似lazytag,但不下传)
    int len;//整个区间被覆盖的总长度
}sh[N*4];
void pushup(int x,int l,int r)
{
    if(sh[x].sum)sh[x].len=xx[r+1]-xx[l];
    else if(l==r)sh[x].len=0;
    else sh[x].len=sh[x<<1].len+sh[x<<1|1].len;//除了覆盖长度外都不要了
}
void modify(int x,int l,int r,int lt,int rt,int w)
{
    if(lt<=l&&rt>=r)
    {
        sh[x].sum+=w;
        pushup(x,l,r);
        return ;
    }
    int mid=(l+r)>>1;
    if(lt<=mid)modify(x<<1,l,mid,lt,rt,w);
    if(rt>mid)modify(x<<1|1,mid+1,r,lt,rt,w);
    pushup(x,l,r);
    return;
}
signed main()
{
    scanf("%lld",&n);
    for(int i=1;i<=n;i++)
    {
        int x1,y1,x2,y2;scanf("%lld%lld%lld%lld",&x1,&y1,&x2,&y2);
        if(x1>x2)swap(x1,x2);
        if(y1>y2)swap(y1,y2);
        bi[++cnt].h=y1,bi[cnt].w=1,bi[cnt].x=x1,bi[cnt].y=x2;
        bi[++cnt].h=y2,bi[cnt].w=-1,bi[cnt].x=x1,bi[cnt].y=x2;
        mx=max(mx,bi[cnt].y);
        mi=min(mi,bi[cnt].x);
        xx[i]=bi[cnt].x;
		xx[i+n]=bi[cnt].y;
    }
    sort(xx+1,xx+2*n+1);
    int tot=unique(xx+1,xx+2*n+1)-xx-2;
    sort(bi+1,bi+cnt+1,cmp);
    for(int i=1;i<=cnt;i++)
    {
        int x=lower_bound(xx+1,xx+tot+2,bi[i].x)-xx;
        int y=lower_bound(xx+1,xx+tot+2,bi[i].y)-xx-1;//离散化了
        modify(1,1,tot,x,y,bi[i].w);
        ans+=sh[1].len*(bi[i+1].h-bi[i].h);
    }
    printf("%lld",ans);
    return 0;
}

标签:总结,node,cnt,return,int,bi,xx,扫描线
From: https://www.cnblogs.com/storms11/p/18385576

相关文章

  • 博弈论算法总结
    正在完善!何为博弈论博弈论,是经济学的一个分支,主要研究具有竞争或对抗性质的对象,在一定规则下产生的各种行为。博弈论考虑游戏中的个体的预测行为和实际行为,并研究它们的优化策略。先来看一道小学就接触过的思维题你和好基友在玩一个取石子游戏。面前有30颗石子,每次只能取一颗......
  • MCU-EFT整改经验总结(一)
    背景:最近设计的PCB跑EFT(电快速脉冲群)±4KV100kHz0.75ms300sL和N都过不了,MCU频繁复位甚至直接像死机了一样,于是和MCU厂说他们的MCU太垃圾,叫他们派FAE过来帮忙处理一下,经过几天整改尝试,跟着FAE学到了不少,并且峰回路转,一波三折。分析干扰路径尝试1:问题出在MCU复位,故原因大......
  • 博客园美化系列总结
    页面定制css代码//鼠标指针body{cursor:url('https://files-cdn.cnblogs.com/files/miluluyo/cursora.ico'),auto;background-color:whitesmoke;//修改背景颜色为半透明}//loading@keyframesspin3D{from{transform:rotate3d(0.5,0.5,0.5,360deg)}to{transfo......
  • 【Unity输入】Unity输入方式总结
    在Unity中,常见的输入方式包括以下几种:1.键盘输入Input.GetKey():用于检测特定键是否被按下。例如,用Input.GetKey(KeyCode.W)检测玩家是否按下“W”键来控制角色移动。Input.GetKeyDown():用于检测某个键在当前帧是否被按下。Input.GetKeyUp():用于检测某个键在当前帧是否......
  • OpenCV Mat和IplImage访问像素的方法总结
    在opencv的编程中,遍历访问图像元素是经常遇到的操作,掌握其方法非常重要,无论是Mat类的像素访问,还是IplImage结构体的访问的方法,都必须扎实掌握,毕竟,图像处理本质上就是对像素的各种操作,访问元素就是各种图像处理算法的第一步。首先先看看图像的是怎么存储的。单通道图像多......
  • Day09_0.1基础学习MATLAB学习小技巧总结(9)——数组运算
    利用空闲时间把碎片化的MATLAB知识重新系统的学习一遍,为了在这个过程中加深印象,也为了能够有所足迹,我会把自己的学习总结发在专栏中,以便学习交流。素材来源“数学建模清风”特此说明:本博客的内容只在于总结在使用matlab中的一些小技巧,并非教程,若想系统的学习MATLAB,也可以移步......
  • Day07_0.1基础学习MATLAB学习小技巧总结(7)——矩阵算数运算
    利用暑假的时间把碎片化的MATLAB知识重新系统的学习一遍,为了在这个过程中加深印象,也为了能够有所足迹,我会把自己的学习总结发在专栏中,以便学习交流。素材来源“数学建模清风”特此说明:本博客的内容只在于总结在使用matlab中的一些小技巧,并非教程,若想系统的学习MATLAB,也可以移......
  • A Brief Introduction to Weakly Supervised Learning 论文总结
    目录论文详情摘要前言IncompleteSupervision(不完全监督)ActiveLearning(主动学习)Semi-SupervisedLearning(半监督学习)ClusterAssumption(集群假设)ManifoldAssumption(流形假设)InexactSupervision(不精确监督)InaccurateSupervision(不准确监督)总结论文详情论文标......
  • Java数据结构栏目总结
     目录数组与稀疏数组队列:自己用数组模拟Queue环形队列,取模【取余】实现.单链表(LinkList)双向链表(Next、Pre)单向环形链表线性结构数组与稀疏数组稀疏数组,很多0值,可用于压缩特点:共n+1行3列,n为不同值的个数(0除外)第一行:数组的行数、列数、不同值的个数第二行:行......
  • Linux firewalld防火墙学习总结
    实践环境CentOS-7-x86_64-DVD-2009简介Firewalld是一种简单的、有状态的、基于区域(zone-based)的防火墙。策略和区域用于组织防火墙规则。网络在逻辑上被划分为多个区域,它们之间的流量可以通过策略进行管理。查看防火墙状态#servicefirewalldstatus或者#systemctls......