1. 程式人生 > 其它 >掃描線模板(離散化版本)

掃描線模板(離散化版本)

掃描線的思想本質上是通過維護有效長度,切割矩形再進行累加。

如何實現維護有效長度?

假設從左往右掃描,掃到一個矩形的左邊時,該矩形的面積開始累加,掃到矩形的右邊時,該矩形不再做貢獻。

--

以下是廢物李一水對該模板的淺薄理解,有錯請及時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"); } }