1 条题解
-
0
自动搬运
来自洛谷,原作者为

pengyirui
最后在线时间:2025/8/15 17:00(预计)|互关条件:paste/c72gso4v#|宣团:(/team/100001)(/team/94966)搬运于
2025-08-24 22:11:18,当前版本为作者最后更新于2025-08-11 17:06:03,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
前置芝士
扫描线算法介绍
扫描线算法,专门用于解决多个矩形的面积并问题,算法实现流程跟名字一样。
这是我从 OIwiki 搬运的算法实现过程视频。通过观察视频,不难发现,计算共分成了 5 个部分,而每个部分的面积,就是一个矩形的面积,直接计算即可(不会的请回到小学再学一次)。
矩形的高可轻易求得,在此不赘述。
现在,重点就是求矩形的底了。再回顾一次视频中扫描方式,可以发现每次扫描到一根线段,我们就会把它加入或者删除。因为每次坐标均为整数,所以可以直接区间加上或者减去 1,最后区间求和即可。
区间加,大家想到什么?线段树对吧。为了加速,考虑使用线段树维护。
在线段树上进行修改,请自行学习,至于树上查询,因为我们需要全部的数量之和,直接查询根节点即可。
整体时间复杂度:,完全可以通过本题。 :::warning[小提醒] 别忘了离散化!!!
别忘了离散化!!!
别忘了离散化!!!
:::正确性证明
对于每行:因为每一次当前行中算的是覆盖的部分,重叠的部分只会计算一次,且不重不漏。(因为每次查找的是大于等于 1 的数字个数)。
对于不同行:由于行不同,自然不会产生重叠。时间复杂度证明
离散化:我采用 sort、unique 和 lower_bound 进行离散化,时间复杂度 。
区间修改操作:线段树操作,时间复杂度 。
查询操作:查询总和即可,时间复杂度 。
总和:省略常数项为 。代码
#include<bits/stdc++.h> #define int long long using namespace std; int n,m,a[3999999],tr[3999999],bj[3999999],lbj[3999999],tot,buc[1008617],len[1008617]; struct nd { int l,r,y,k; }tree[1008617]; void build(int l,int r,int now) { len[now]=buc[r]-buc[l-1]; if(l==r)return; int mid=l+((r-l)/2); build(l,mid,now*2); build(mid+1,r,now*2+1); } void update(int u) { if(lbj[u]>0)tr[u]=len[u]; else tr[u]=tr[2*u]+tr[2*u+1]; } void xg(int l,int r,int to,int l1,int r1,int now) { if(l<=l1&&r1<=r) { lbj[now]+=to; update(now); return; } int mid=l1+(r1-l1)/2; if(l<=mid)xg(l,r,to,l1,mid,now*2); if(r>mid)xg(l,r,to,mid+1,r1,now*2+1); update(now); } bool cmp(nd aa,nd bb) { return aa.y<bb.y; } signed main() { cin>>n; for(int i=1;i<=n;i++) { int xl,xr,yl,yr; cin>>xl>>yl>>xr>>yr; tree[i].l=xl; tree[i].r=xr; tree[i].y=yl; tree[i].k=1ll; tree[i+n].l=xl; tree[i+n].r=xr; tree[i+n].y=yr; tree[i+n].k=-1ll; buc[++tot]=xl; buc[++tot]=xr; } sort(buc+1,buc+tot+1); tot=unique(buc+1,buc+1+tot)-buc-1; for(int i=1;i<=2*n;i++) { tree[i].l=lower_bound(buc+1,buc+1+tot,tree[i].l)-buc; tree[i].r=lower_bound(buc+1,buc+1+tot,tree[i].r)-buc; } sort(tree+1,tree+1+2*n,cmp); build(1,tot,1); int ans=0; for(int i=1;i<=2*n;i++) { ans+=(tree[i].y-tree[i-1].y)*tr[1]; xg(tree[i].l+1,tree[i].r,tree[i].k,1,tot,1); } cout<<ans; return 0; }小练习
别看我,我除了前两题全都不会做……
【模板】离线二维数点
矩形周长
扇形面积并
纵坐标扫描线
洪水
- 1
信息
- ID
- 4492
- 时间
- 1000ms
- 内存
- 512MiB
- 难度
- 5
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者