扫描线
首先考虑这样一个问题:
给你
我会暴力! 其中 int
范围内的数。
我会容斥! 显然会 TLE
所以我们需要考虑一种更快速更容易维护的方式。
扫描线,顾名思义就是一条平行于坐标轴的线从第一个矩形的左边一直扫描到最后一个矩形的右边。
考虑维护每次扫描线碰到的矩形的边长,只需要将这次碰到的边长乘上这次碰到的边的横坐标与上次碰到的边的横坐标的差就可以算出两端扫描线之间的距离。
那么如何维护扫描线扫到的矩形的边长呢?
可以使用一个变量记录这条边是矩形的左边还是右边,因为可以发现的是,扫描线的长度是随着每次碰到一条矩形的边而不断变化的,所以只需要一个变量 cover
来记录某个点是否被扫描线所覆盖,如果当前的扫描线扫到的边是左边就 cover++
,是右边就 cover--
。
所以每次扫描线扫到一条新的边,就只需要更改所有扫描线覆盖的边的 cover
值即可。
这种操作不就是线段树的区间修改操作吗?
整理一下思路,首先我们在
需要注意的是,由于坐标的数值很大,所以我们需要对坐标进行离散化操作。
struct Line{
int x;
int y1,y2;
int state;
bool operator < (Line a){ return x < a.x; }
}line[N];
struct Node{
int l,r;
int cover;
long long len;
}tree[N<<3];
inline void push_up(int p){
if(tree[p].cover) tree[p].len = tree[p].r - tree[p].l;
else tree[p].len = tree[p<<1].len+tree[p<<1|1].len;
}
void build(int p,int l,int r){
tree[p].l = v[l] , tree[p].r = v[r];
if(r - l <= 1) return;
int mid = l + r >>1;
build(p<<1,l,mid);
build(p<<1|1,mid,r);
}
void modify(int p,int l,int r,int k){
if(l <= tree[p].l && tree[p].r <= r){
tree[p].cover += k;
push_up(p);
return;
}
if(l < tree[p<<1].r) modify(p<<1,l,r,k);
if(r > tree[p<<1|1].l) modify(p<<1|1,l,r,k);
push_up(p);
}
int main(){
int n = read();
for(int i=1;i<=n;i++){
int a = read() , b = read() , c = read() , d = read();
v[i] = b,v[n+i] = d;
line[i] = (Line){a,b,d,1} , line[n+i] = (Line){c,b,d,-1};
}
sort(v+1,v+(n<<1)+1);
sort(line+1,line+(n<<1)+1);
build(1,1,n<<1);
unsigned long long ans = 0;
for(int i=1;i<=n<<1;i++){
ans += tree[1].len * (line[i].x - line[i-1].x);
modify(1,line[i].y1,line[i].y2,line[i].state);
}
printf("%llu\n",ans);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】