我的第一篇博客就是扫描线。虽然那时候什么也不懂,也非常幼稚,甚至不知扫描线的原理是如何,只是一门心思地去做,就像面对未知的生活。
扫描线处理矩阵面积之和的问题,当然它们会有互相覆盖而不能直接加起来。
扫描线就是从下往上一次扫描“线”,然后用线将图分成多个区域,累加即可。用线段树记录横坐标此时扫描线处的长度。
用Xi表示第i条竖直的线(用来划分区间)
用line结构体表示线水平的线
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #define R register using namespace std; typedef long long ll; inline int read() { int x=0,w=0;char c=getchar(); while(!isdigit(c))w|=c=='-',c=getchar(); while(isdigit(c))x=(x<<3)+(x<<1)+(c^48),c=getchar(); return w?-x:x; } const int maxn=1e6+10; struct Line{ ll l,r,h; int val; bool operator < (const Line &zp) const {return h<zp.h;} }line[maxn<<1]; int n; ll X[maxn<<1]; struct SegmentTree { #define ls (ro<<1) #define rs (ro<<1|1) int l,r,sum; struct tree{ int l,r,sum; ll len; }e[maxn<<2]; inline void pushup(int ro) { if(e[ro].sum)e[ro].len=X[e[ro].r+1]-X[e[ro].l]; else e[ro].len=e[ls].len+e[rs].len; } void build(int ro,int l,int r) { e[ro].l=l,e[ro].r=r; if(l==r)return; int mid=l+r>>1; build(ls,l,mid); build(rs,mid+1,r); } void update(int ro,int l,int r,int val) { if(X[e[ro].r+1]<=l or r<=X[e[ro].l])return; if(l<=X[e[ro].l] and X[e[ro].r+1]<=r) { e[ro].sum+=val; pushup(ro); return; } update(ls,l,r,val); update(rs,l,r,val); pushup(ro); } #undef ls #undef rs }seg; int main() { n=read(); for(int i=1;i<=n;i++) { ll x1=(ll)read(),y1=(ll)read(),x2=(ll)read(),y2=(ll)read(); line[(i<<1)-1]=(Line){x1,x2,y1,1}; line[i<<1]=(Line){x1,x2,y2,-1}; X[(i<<1)-1]=x1,X[i<<1]=x2; } n<<=1; sort(line+1,line+n+1); sort(X+1,X+n+1); int cnt=unique(X+1,X+n+1)-X-1; seg.build(1,1,cnt-1); ll ans=0; for(register int i=1;i<n;i++) { seg.update(1,line[i].l,line[i].r,line[i].val); ans+=seg.e[1].len*(line[i+1].h-line[i].h); } printf("%lld ",ans); return 0; }