扫描线模板(离散化版本)
扫描线的思想本质上是通过维护有效长度,切割矩形再进行累加。
如何实现维护有效长度?
假设从左往右扫描,扫到一个矩形的左边时,该矩形的面积开始累加,扫到矩形的右边时,该矩形不再做贡献。
--
以下是废物李一水对该模板的浅薄理解,有错请及时cue我..
为什么把pushup写到了update return的地方?
你看,平时放lazytag时是不是update放一遍,query放一遍..
没写query的话,那份下放就一起塞到update里了,保证查询sum[1]时总是对的;
为啥不写query,只需要知道sum【1】的值即可,又不想知道其他区间的值;
为啥update发现是叶子节点的时候可以直接return不做修改了?
因为叶子节点的爸爸在push的时候把它儿子给改了;
--
#include<bits/stdc++.h> using namespace std; struct lys{ double up,down,x; int inout; }line[500000]; double sum[500000],cover[900000],yy[500000]; bool cmp(lys a,lys b) { if(a.x==b.x) return a.inout>b.inout; return a.x<b.x; } void push(int rt,int l,int r) { if(cover[rt]>0) sum[rt]=yy[r]-yy[l]; else if(l+1==r) sum[rt]=0; else sum[rt]=sum[rt<<1]+sum[rt<<1|1]; } void update(int rt,int l,int r,int ul,int ur,int pd) { if(r<ul||l>ur) return; if(l>=ul&&r<=ur) { cover[rt]+=pd; push(rt,l,r); return; } if(l+1==r) { return; } int mid=(l+r)>>1; if(ul<=mid) { update(rt<<1,l,mid,ul,ur,pd); } if(ur>mid) { update(rt<<1|1,mid,r,ul,ur,pd); } push(rt,l,r); } int main( ) { //上左下右边 //freopen("lys.in","r",stdin); int n,k=0; while(cin>>n) { k++; if(n==0) break; double x,y,x2,y2; int cnt=0; for(int i=1;i<=n;i++) { scanf("%lf%lf%lf%lf",&x,&y,&x2,&y2); cnt++; lys u; u.x=x;u.up=y2;u.down=y;u.inout=1; line[cnt]=u; yy[cnt]=y; cnt++; u.x=x2;u.up=y2;u.down=y;u.inout=-1; line[cnt]=u; yy[cnt]=y2; } sort(line+1,line+cnt+1,cmp); sort(yy+1,yy+cnt+1); int len=unique(yy+1,yy+cnt+1)-(yy+1); memset(sum,0,sizeof(sum)); memset(cover,0,sizeof(cover)); double ans=0; for(int i=1;i<=cnt;i++) { //cout<<sum[1]<<" "<<line[i].x<<" "<<line[i-1].x<<endl; ans+=sum[1]*(line[i].x-line[i-1].x); int yl=lower_bound(yy+1,yy+len+1,line[i].down)-yy; int yr=lower_bound(yy+1,yy+len+1,line[i].up)-yy; // cout<<yl<<" "<<yr<<endl; update(1,1,len,yl,yr,line[i].inout); } printf("Test case #%d\n",k); printf("Total explored area: %.2lf\n",ans); printf("\n"); } }