首页 > 其他分享 >线段树之扫描线

线段树之扫描线

时间:2023-04-11 09:55:43浏览次数:50  
标签:int 线段 长方形 扫描线 X2 X1

P5490 【模板】扫描线

给你 n 个位于平面直角坐标系上的长方形,它们之间可能互相重叠,求这些长方形的面积。

很显然,对于长方形之间有重叠部分,如果采用容斥原理,不仅非常复杂,而且难以实现。

事实上,既然题目已经给了我们这些长方形的顶点,这些长方形最终构成的图形可以被坐标轴划分为 m 个长方形。

而我们只需要处理这 m 个长方形面积之和即可。

如果我们采用 y轴 划分,每一个长方形对最终面积的贡献取决其在 [y1,y2] 这段区间里所占的 x 轴的长度,此时我们所求的,就是所有属于这段区间的 x 的并集。

这时候,扫描线的思路就登场了! 引入入边,出边的概念,对这个集合进行维护,入边则添加,出边则删除,采用线段树维护 x 的并集。

由于题目所给数据范围过大,我们需要进行离散化以及采用线段树动态开点操作(很简单的)。

 

此时,思路已经很清晰了。

 

上代码:

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e6+10;
int n,m,t,X1,X2,Y1,Y2,ans;
int x[N<<1];
struct node{
    int l,r,cnt,len;
}tree[N<<2];
struct Line{
    int l,r,h,flag;
    bool operator<(const Line &rhs) const{
        return h<rhs.h;
    }
}line[N<<1];
void push_up(int k){
    if(tree[k].cnt) tree[k].len=(x[tree[k].r+1]-x[tree[k].l]);
    else tree[k].len=tree[k<<1].len+tree[(k<<1)+1].len;
}
void build(int k,int l,int r){
    tree[k].l=l,tree[k].r=r;
    if(l==r){
        tree[k].len=tree[k].cnt=0;return;
    }
    int mid=l+r>>1;
    build(k<<1,l,mid);
    build(k<<1|1,mid+1,r);
    push_up(k);
}
void update(int k,int l,int r,int w){
    if(x[tree[k].r+1]<=l||x[tree[k].l]>=r) return;
    if(x[tree[k].l]>=l&&x[tree[k].r+1]<=r){
        tree[k].cnt+=w;
        push_up(k);
        return ;
    }
    int mid=tree[k].l+tree[k].r>>1;
    update(k<<1,l,r,w);
    update(k<<1|1,l,r,w);
    push_up(k);
}
signed main(){
    cin>>n;
    for(int i=1;i<=n;++i){
        cin>>X1>>Y1>>X2>>Y2;
        x[2*i-1]=X1;x[2*i]=X2;
        line[2*i-1]={X1,X2,Y1,1};
        line[2*i]={X1,X2,Y2,-1};
    }
    n<<=1;
    sort(line+1,line+n+1);
    sort(x+1,x+1+n);
    m=unique(x+1,x+1+n)-x-1;
    build(1,1,m-1);
    for(int i=1;i<n;++i){
        update(1,line[i].l,line[i].r,line[i].flag);
        ans+=(tree[1].len*(line[i+1].h-line[i].h));
    }
    cout<<ans;
    return 0;
}

 

标签:int,线段,长方形,扫描线,X2,X1
From: https://www.cnblogs.com/buleeyes/p/17305210.html

相关文章

  • 线段树分治
    线段树分治线段树分治,解决的是这样一类问题:有一个时间轴,有一些操作,这些操作在时间轴上每一个的作用范围是一个区间;在某些时间或者全局询问一些关于操作效果的问题。它的重要效果是:一是可以把所有删除操作改成撤回操作(也就是撤回当前最近一个操作,而不是删除之前随便一个操作),可以......
  • hdu-4533(线段树+区间合并)
    约会安排HDU-4553跟hdu-1540(线段树+区间合并)-魏老6-博客园(cnblogs.com)是一样,但是要写两个线段树。线段树维护,最长前缀pre,最长后缀suf,以及最大连续连续区间sum。1代表空,0代表时间被占了还有几个注意事项:当是DS时,只能查询和修改屌丝树;当是NS时,先判断屌丝树能不......
  • 可持久化线段树(主席树)
              代码#include<bits/stdc++.h>usingnamespacestd;constintN=4e7+10;intn,m,t,top,rt,mode,x,y;intf[N],a[N],root[N];structkkk{intl,r,val;}tree[N];intclone(intnode){top++;tree[top]=tree[node];return......
  • poj-3367(线段树+区间合并)
    HotelPOJ-3667思路:与hdu-1540(线段树+区间合并)-魏老6-博客园(cnblogs.com)类似,只不过是区间修改,多维护一个最大连续区间sum。#define_CRT_SECURE_NO_WARNINGS1#include<algorithm>#include<fstream>#include<iostream>#include<cstdio>#include<deque>#includ......
  • hdu-1540(线段树+区间合并)
    TunnelWarfareHDU-1540思路:没被摧毁的村庄为1,否则为0,用len记录线段树维护区间的两个信息:前缀最长1的序列pre后缀最长1的序列suf父节点与左右子节点的关系://lc为左节点,rc为右节点1.若左右结点都不满1,则tr[p].pre=tr[lc].pre,tr[p].suf=tr[rc].suf2.若左节点满1,tr......
  • [蓝桥杯 2021 国 AB] 翻转括号序列(线段树上二分)
    [蓝桥杯2021国AB]翻转括号序列题目描述给定一个长度为\(n\)的括号序列,要求支持两种操作:将\(\left[L_{i},R_{i}\right]\)区间内(序列中的第\(L_{i}\)个字符到第\(R_{i}\)个字符)的括号全部翻转(左括号变成右括号,右括号变成左括号)。求出以\(L_{i}\)为左端点......
  • CAD如何测量连续线段长度?CAD测量连续线段长度步骤
    在CAD绘图过程中,经常会绘制一些连续的线段,如果想要知道这些连续线段长度的话,该怎么操作吗?CAD如何测量连续线段长度?下面小编就以浩辰CAD软件为例来给大家分享一下CAD测量连续线段长度的具体操作步骤吧!CAD测量连续线段长度步骤:浩辰CAD软件中已经考虑到了这种需求,在CAD测量命令(DIST......
  • 动态开点线段树&线段树合并学习笔记
    动态开点线段树使用场景\(4\timesn\)开不下。值域需要平移(有负数)。什么时候开点显然,访问的节点不存在时(只会在修改递归时开点)。trick区间里面有负数时,\(mid=(l+R-1)/2\)。防止越界。例如区间\([-1,0]\)。开点上限考虑到update一次最多开\(\logV\)个......
  • 第二十届浙大城市学院程序设计竞赛 I.Magic Tree DFS序线段树
    传送门大致思路:  我们知道dfs序上的整颗子树dfs序编号连续,因为每次删除一个点或者新增一个点都导致子树上所有点的深度加一或者减一。由于是区间修改所以我们考虑dfs序上建线段树。  #include<iostream>#include<cstring>#include<iomanip>#include<algorithm>#in......
  • 区间和线段树封装模板
    区间和线段树封装模板,开箱即用注意:线段树大小最多支持\(2^{30}-1\)个数声明方法:SegSumTree<typename>st,typename为线段树存储的类型(建议只填写整数类型),建立一颗空线段树,后续必须先用rebuild或resize初始化SegSumTree<typename>st(n)建立一颗定义了长度的空线段树,n为线段树维......