線段樹+掃描線
阿新 • • 發佈:2020-10-05
掃描線求面積
模型
有若干個矩形,給出每個矩形的左下和右上座標,問這些矩形的面積交。
就是陰影部分的面積
演算法流程
用掃描線,我們按每個矩形分成為兩條掃描線,上掃描線(-)和下掃描線(+)。
struct Line {
double l, r, h;//覆蓋的x軸起點和終點,高度h
int k;//上/下邊
}a[10005];
那麼面積就是|這條掃描線的高度-上條掃描線的高度|*(掃描線覆蓋的x軸區間大小)
\(ans+=(a[i].h-a[i-1].h)*(掃描線覆蓋的x軸區間大小)\)
掃描線覆蓋的x軸區間大小:用線段樹維護,下邊線上段樹上加,上邊線上段樹上減。
把掃描線排序後,開始處理,h相同先處理+
加入第一條掃描線前:
\(ans+=(a[1].h-a[0].h)*(0)// ans=0\)
加入第二條掃描線前:
掃描線覆蓋的x軸區間大小=2
\(ans+=(a[2].h-a[1].h)*(2),因為a[2].h==a[1].h//ans=0\)
加入第4條掃描線前,掃描線覆蓋的x軸區間大小=4。
\(ans+=(a[1].h-a[0].h)*(4)// ans+=1*4=4\)
實際上這次求的是這部分面積:
加入第4條掃描線前,掃描線覆蓋的x軸區間大小=5。
\(ans+=(a[1].h-a[0].h)*(5)// ans+=1*5=9\)
這次求的面積:
加入第5條掃描線前,掃描線覆蓋的x軸區間大小=4。
\(ans+=(a[1].h-a[0].h)*(4)// ans+=2*4=17\)
這次求的面積:
加入第6條掃描線前,掃描線覆蓋的x軸區間大小=2。
這次求的面積:
所有的面積都不重不漏的計算出來了。
具體實現
把x座標離散化。用lza標記這個區間是否全部覆蓋。
if(lza[i])sum[i]=這個區間的長度
else{
if(i是葉子節點){
sum[i]=0
}
else{
sum[i]=sum[i<<1]+sum[i<<1|1]
}
}
這樣就可以維護加線段和減線段了
#include <map> #include <set> #include <cmath> #include <queue> #include <cstdio> #include <vector> #include <climits> #include <cstring> #include <cstdlib> #include <iostream> #include <algorithm> #define LL long long using namespace std; double z[205]; struct Tree { int laz[2000005]; double sum[2000005]; void BT(int i, int l, int r) { sum[i]=laz[i]=0; if(l==r) return ; int mid=l+r>>1; BT(i<<1, l, mid), BT(i<<1|1, mid+1, r); } void psuh_up(int i, int l, int r) { if(laz[i]) { //全部覆蓋 sum[i]=z[r]-z[l-1]; } else if(l==r) { //葉子節點 sum[i]=0; } else { sum[i]=sum[i<<1]+sum[i<<1|1]; } } void up_data(int i, int l, int r, int L, int R, int val) { if(R<L) return ; if(l==L&&r==R) { laz[i]+=val; psuh_up(i, l, r); return ; } int mid=l+r>>1; if(R<=mid) up_data(i<<1, l, mid, L, R, val); else if(L>mid) up_data(i<<1|1, mid+1, r, L, R, val); else up_data(i<<1, l, mid, L, mid, val), up_data(i<<1|1, mid+1, r, mid+1, R, val); psuh_up(i, l, r); } } T; struct Line { double l, r, h; int k;//上/下邊 }a[105]; int cmp1(double a, double b){return a<b;} int cmp2(const Line &a, const Line &b){return a.h==b.h?a.k>b.k:a.h<b.h;} int main() { int n, cas=1; double x, y, x2, y2; while(scanf("%d", &n), n) { for(int i=1; i<=n; i++) { scanf("%lf%lf%lf%lf", &x, &y, &x2, &y2); a[i*2-1]={x, x2, y, 1}; a[i*2]={x, x2, y2, -1}; z[i*2-1]=x, z[i*2]=x2; } //離散化x座標 sort(z+1, z+2*n+1, cmp1); int cnt=unique(z+1, z+2*n+1)-z-1; T.BT(1, 1, cnt); for(int i=1; i<=2*n; i++){ a[i].l=lower_bound(z+1, z+cnt+1, a[i].l)-z; a[i].r=lower_bound(z+1, z+cnt+1, a[i].r)-z; } double ans=0; sort(a+1, a+2*n+1, cmp2); for(int i=1; i<=2*n; i++){ double H=a[i].h-a[i-1].h; ans+=H*T.sum[1]; T.up_data(1, 1, cnt, a[i].l+1, a[i].r, a[i].k); } printf("Test case #%d\n", cas++); printf("Total explored area: %.2f\n\n", ans); } return 0; } /* 2 10 10 20 20 15 15 25 25.5 0 */