浅谈树状数组与线段树:https://www.cnblogs.com/AKMer/p/9946944.html

题目传送门:https://www.lydsy.com/JudgeOnline/problem.php?id=1382

扫描线模板题。假设有一条直线从左往右扫过平面,那么每一单位时间内这条直线被矩形覆盖的长度的和就是矩形们的面积。而直线上被覆盖的长度只会在经过矩阵的竖边时发生变化,当我们扫到一条矩阵的左边时就在该左边所覆盖的区间上打标记表示这一段区间已经被覆盖,扫到右边时减掉。一共有\(2*n\)条边,也就一共有\(2*n-1\)个区间,每个区间的面积就是当前直线上被覆盖的长度乘以构成这个区间的两条线段的\(x\)轴差值。

我们将\(2*n\)条边按\(x\)轴坐标排序,每条线段的\(y\)轴坐标离散化,然后用线段树维护每个\(y\)轴上的区间被多少条线段覆盖了。如果区间[\(l,r\)](意思是第\(l\)条线段到第\(r+1\)条线段构成的区间)被覆盖的次数大于\(0\),那么这一段的线段被覆盖的长度就是\(y[r+1]-y[l]\),否则就由两个儿子节点更新过来。因为边都是成对出现的,所以覆盖标记不用下传。

每次直接用根节点的覆盖长度乘以两条线段的\(x\)坐标的差值累加面积即可。

时间复杂度:\(O(nlogn)\)

空间复杂度:\(O(n)\)

代码如下:

#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long ll; const int maxn=2e4+5; ll ans;
int n,cnt;
int tmp[maxn]; int read() {
int x=0,f=1;char ch=getchar();
for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
for(;ch>='0'&&ch<='9';ch=getchar())x=x*10+ch-'0';
return x*f;
} struct line {
int x,st,ed,mark; line() {} line(int _x,int _st,int _ed,int _mark) {
x=_x,st=_st,ed=_ed,mark=_mark;
} bool operator<(const line &a)const {
return x<a.x;
}
}p[maxn]; struct segment_tree {
int len[maxn<<2],cnt[maxn<<2]; void updata(int p,int l,int r) {
if(cnt[p])len[p]=tmp[r+1]-tmp[l];//如果有被线段覆盖就直接加进全部长度
else if(l==r)len[p]=0;//如果是叶子节点就等于0,
else len[p]=len[p<<1]+len[p<<1|1];//否则用儿子更新
} void change(int p,int l,int r,int L,int R,int v) {
if(L<=l&&r<=R) {
cnt[p]+=v;
updata(p,l,r);//每次覆盖都需要更新
return;
}
int mid=(l+r)>>1;
if(L<=mid)change(p<<1,l,mid,L,R,v);
if(R>mid)change(p<<1|1,mid+1,r,L,R,v);
updata(p,l,r);
}
}T; int main() {
n=read();
for(int i=1;i<=n;i++) {
int x1=read(),y1=read(),x2=read(),y2=read();
tmp[(i<<1)-1]=y1,tmp[i<<1]=y2;
p[(i<<1)-1]=line(x1,y1,y2,1);
p[i<<1]=line(x2,y1,y2,-1);
}sort(p+1,p+2*n+1);sort(tmp+1,tmp+2*n+1);
cnt=unique(tmp+1,tmp+2*n+1)-tmp-1;
for(int i=1;i<=2*n;i++) {
p[i].st=lower_bound(tmp+1,tmp+cnt+1,p[i].st)-tmp;
p[i].ed=lower_bound(tmp+1,tmp+cnt+1,p[i].ed)-tmp;
}//排序和离散化
for(int i=1;i<=2*n;i++) {
ans+=1ll*T.len[1]*(p[i].x-p[i-1].x);//累加第i-1号区间的面积
T.change(1,1,cnt-1,p[i].st,p[i].ed-1,p[i].mark);//更新直线上被覆盖的长度
}printf("%lld\n",ans);
return 0;
}

最新文章

  1. How to copy remote computer files quickly to local computer
  2. Linux关于vm虚拟机复制后无法启动网卡
  3. 【hdu1394】Minimum Inversion Number
  4. 字节流与字符流的区别&amp;&amp;用字节流好还是用字符流好?
  5. [转]新兵训练营系列课程——平台RPC框架介绍
  6. 浅谈C#抽象方法、虚方法、接口
  7. 288. Unique Word Abbreviation
  8. Android UI主线程与子线程
  9. font简写语法
  10. 关于Videodownload helper的下载问题
  11. Jenkins构建时间Poll Scm的设置
  12. Java工程师成神之路思维导图
  13. 折腾Java设计模式之状态模式
  14. 基于PLC1850平台的UDP报文接收与发送
  15. 学习笔记TF058:人脸识别
  16. h5笔记02
  17. k8s系列~mgr的应用
  18. SpingBoot —— RestTemplate的配置
  19. Java Try-with-resources
  20. [毕业设计][期末作业]二手闲置小程序 免费信息发布系统功能源码(小程序+php后台管理)

热门文章

  1. Android 进阶自定义 ViewGroup 自定义布局
  2. Verilog代码规范(持续更新)
  3. 字符串转化成十六进制输出StrToHex(Delphi版、C#版)
  4. nginx could not build the server_names_hash 解决方法
  5. 018 nginx与第三模块整合[一致性哈希模块整合]
  6. Python中urllib2总结
  7. c# combobox 绑定枚举方式
  8. 动态内存分配(Dynamic memory allocation)
  9. 【BZOJ1776】[Usaco2010 Hol]cowpol 奶牛政坛 树的直径
  10. about gnu bash shell