線段樹掃描線總結,求面積,求周長(hdu1542,poj1177)
阿新 • • 發佈:2018-11-09
這兩天學了掃描線相關內容,特來總結一下:
求面積:
假設是從下往上掃描
(1)離散橫座標
(2)對陣列由高度從小到大排序
(3)對每一條橫線都進行更新,sum[1]表示的是區間橫座標覆蓋的長度,比如說離散化後更新[1,4]區間,實際上呼叫的是update(1,3),這裡是因為我們在push_up的時候,可以求出正確結果sum[rt]=x[r+1]-x[l],這樣就可以求出[1,4]
(4)在對每一條橫線更新後,我們得到了區間的橫座標,那麼乘當向上一條線的高度和當前高度的差,把每次迴圈求出來的面積加起來~
程式碼如下:
#include<iostream> #include<cstdio> #include<algorithm> #include<string> #include<cstring> #include<queue> #include<cmath> #include<set> #include<map> #define ll long long #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 using namespace std; const int N=110; double X[N<<1]; double tree[N<<3]; int add[N<<3]; struct A{ double l,r,h; int f; }cor[N<<1]; bool cmp(A a,A b){ return a.h<b.h; } void push_up(int l,int r,int rt){ if(add[rt]){ tree[rt]=X[r+1]-X[l]; } else if(l==r)tree[rt]=0; else tree[rt]=tree[rt<<1]+tree[rt<<1|1]; } void update(int L,int R,int C,int l,int r,int rt){ if(L<=l&&R>=r){ add[rt]+=C; push_up(l,r,rt); return ; } int m=(l+r)>>1; if(L<=m)update(L,R,C,lson); if(R>m)update(L,R,C,rson); push_up(l,r,rt); } int main(){ int n,cas=1; double x1,x2,y1,y2; while(scanf("%d",&n)!=EOF){ if(n==0)break; int cnt=0; for(int i=1;i<=n;i++){ scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2); X[++cnt]=x1; cor[cnt].l=x1; cor[cnt].r=x2; cor[cnt].h=y1; cor[cnt].f=1; X[++cnt]=x2; cor[cnt].l=x1; cor[cnt].r=x2; cor[cnt].h=y2; cor[cnt].f=-1; } sort(X+1,X+1+cnt); sort(cor+1,cor+1+cnt,cmp); int nn=unique(X+1,X+1+cnt)-X-1;//表示去重後X陣列的大小[1,nn] memset(tree,0,sizeof(tree)); memset(add,0,sizeof(add)); double ans=0; for(int i=1;i<=cnt;i++){ int L=lower_bound(X+1,X+1+nn,cor[i].l)-X; int R=lower_bound(X+1,X+1+nn,cor[i].r)-X-1; update(L,R,cor[i].f,1,nn,1); ans+=tree[1]*(cor[i+1].h-cor[i].h); } printf("Test case #%d\n",cas++); printf("Total explored area: %.2f\n\n",ans); } } /* 3 10 10 20 20 5 15 10 20 10 25 25 30 */
求周長:
與求面積相似,只是每次加的橫向長度等於sum[1]-last(last記錄上一個sum[1])
seg陣列記錄有幾條豎線,seg*(h[i+1]-h[i])
seg的原理可以這麼理解:
程式碼如下:
#include<iostream> #include<cstdio> #include<algorithm> #include<string> #include<cstring> #include<queue> #include<cmath> #include<set> #include<map> #define ll long long #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 using namespace std; const int N=5005; int X[N<<1]; struct A{ int l,r,h,f; }cor[N<<1]; int sum[N<<3],add[N<<3],seg[N<<3],lseg[N<<3],rseg[N<<3]; bool cmp(A a,A b){ return a.h<b.h; } void push_up(int l,int r,int rt){ if(add[rt]){//全覆蓋 sum[rt]=X[r+1]-X[l]; seg[rt]=2; lseg[rt]=1; rseg[rt]=1; } else if(l==r){//葉子節點且沒被覆蓋 sum[rt]=seg[rt]=lseg[rt]=rseg[rt]=0; } else{//非全覆蓋(不覆蓋或半覆蓋) sum[rt]=sum[rt<<1]+sum[rt<<1|1]; seg[rt]=seg[rt<<1]+seg[rt<<1|1]; lseg[rt]=lseg[rt<<1]; rseg[rt]=rseg[rt<<1|1]; if(rseg[rt<<1]&&lseg[rt<<1|1])seg[rt]-=2; } } void update(int L,int R,int C,int l,int r,int rt){ if(L<=l&&R>=r){ add[rt]+=C; push_up(l,r,rt); return ; } int m=(l+r)>>1; if(L<=m)update(L,R,C,lson); if(R>m)update(L,R,C,rson); push_up(l,r,rt); } int main(){ int n; scanf("%d",&n); int x1,x2,y1,y2; int cnt=0; memset(sum,0,sizeof(sum)); memset(lseg,0,sizeof(lseg)); memset(rseg,0,sizeof(rseg)); for(int i=1;i<=n;i++){ scanf("%d%d%d%d",&x1,&y1,&x2,&y2); X[++cnt]=x1; cor[cnt].l=x1; cor[cnt].r=x2; cor[cnt].h=y1; cor[cnt].f=1; X[++cnt]=x2; cor[cnt].l=x1; cor[cnt].r=x2; cor[cnt].h=y2; cor[cnt].f=-1; } sort(X+1,X+1+cnt); sort(cor+1,cor+1+cnt,cmp); int nn=unique(X+1,X+1+cnt)-X-1; int last=0,ans=0; for(int i=1;i<=cnt;i++){ int L=lower_bound(X+1,X+1+nn,cor[i].l)-X; int R=lower_bound(X+1,X+1+nn,cor[i].r)-X-1; update(L,R,cor[i].f,1,nn,1); ans+=abs(sum[1]-last); ans+=seg[1]*(cor[i+1].h-cor[i].h); last=sum[1]; } printf("%d\n",ans); }