学习笔记 扫描线(面积并)
模板题:https://www.luogu.org/problem/P5490
这个是用于求面积并的扫描线。
显然只有矩形的两边会使答案发生变化。
所以对每一个边做出一个四元组(x,yl,yh,1/-1)
x就是x坐标 yl,yh是这条线的纵坐标,1为左端点,-1为右端点。
然后就可以用线段树模拟线去扫描。
在线段树里维护两个信息cnt,len。
cnt表示有多少个点覆盖,len表示覆盖的长度。
这样的话就可以ans+=(len(i)*x差)。
代码如下:
#include<bits/stdc++.h> #define int long long #define ll long long using namespace std; const int maxn=1e6+10; int n,tot,b[maxn<<1],val[maxn<<1],maxx; struct n1{ int x,yl,yh,fl; }e[maxn<<1]; struct node{ ll len,cnt; #define len(x) t[x].len #define cnt(x) t[x].cnt }t[maxn<<1]; inline bool cmp1(n1 x,n1 y){ return x.x==y.x ? x.fl<y.fl : x.x<y.x; } inline void pushup(int p,int l,int r){ if(l==r&&r==maxx) return; if(cnt(p)) len(p)=val[r+1]-val[l]; else len(p)=len(p<<1)+len(p<<1|1); } inline void add(int p,int l,int r,int x,int y,int d){ if(x<=l&&r<=y){ cnt(p)+=d; pushup(p,l,r); return; } int mid=(l+r)>>1; if(x<=mid) add(p<<1,l,mid,x,y,d); if(y>mid) add(p<<1|1,mid+1,r,x,y,d); pushup(p,l,r); } signed main() { scanf("%lld",&n); for(int i=1;i<=n;i++){ int x,y,xx,yy; scanf("%lld%lld%lld%lld",&x,&y,&xx,&yy); e[++tot].x=x;b[tot]=y; e[tot].yl=y;e[tot].yh=yy;e[tot].fl=1; e[++tot].x=xx;b[tot]=yy; e[tot].yl=y;e[tot].yh=yy;e[tot].fl=-1; } sort(b+1,b+1+tot); tot=unique(b+1,b+1+tot)-b-1; for(int i=1;i<=2*n;i++){ int h1=lower_bound(b+1,b+1+tot,e[i].yh)-b; int h2=lower_bound(b+1,b+1+tot,e[i].yl)-b; val[h1]=e[i].yh;val[h2]=e[i].yl; e[i].yh=h1;e[i].yl=h2; maxx=max(maxx,h1); } sort(e+1,e+1+2*n,cmp1); ll ans=0; for(int i=1;i<=2*n;i++){ add(1,1,2*n,e[i].yl,e[i].yh-1,e[i].fl); ans+=len(1)*(e[i+1].x-e[i].x); } printf("%lld\n",ans); //system("pause"); return 0; }