poj1511,線段樹掃描線面積
阿新 • • 發佈:2018-11-10
經典題,線段樹掃描線其實類似區間更新,一般的做法是想象一根掃描線從上掃到下或者從左掃到右,本題的做法是從上掃到下
#include<iostream> #include<cstring> #include<cstdio> #include<algorithm> #define maxn 2000 #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 using namespace std; struct Seg{ double l,r,h; int d; Seg(){} Seg(double a,double b,double c,int dd):l(a),r(b),h(c),d(dd){} bool operator<(const Seg & a)const{ return h<a.h; }//從下往上掃描 }segs[maxn];//橫線段 double data[maxn]; int tot,m;//data統計高度 int cnt[maxn<<2];//覆蓋了這一整個區間的入邊數 - 覆蓋了這一整個區間的出邊數 double sum[maxn<<2];//區間當前被覆蓋的長度 inline void pushup(intl,int r,int rt){ //前兩個if對應的是update中(L<=l && R>=r)的pushup,後一個if對應的是分開更新後的update if(cnt[rt])//如果這個區間都被覆蓋了 sum[rt]=data[r+1]-data[l]; else if (l==r)//如果是單位段並且cnt[rt]==0,說明這一段就是沒有被覆蓋 sum[rt]=0; else sum[rt]=sum[rt<<1]+sum[rt<<1|1]; } //更新函式update:如果整個區間被更新,分三種情況:1.這個區間被完全覆蓋 2.這個區間是空白單位區間(沒有子區間) 3.這個區間沒有被完全覆蓋void update(int L,int R,int c,int l,int r,int rt){ if(L<=l && R>=r){ cnt[rt]+=c; pushup(l,r,rt);//為什麼這裡也會有pushup?因為pushup的功能不只是合併兩個區間而已,它還能計算這個區間的覆蓋長度 return; } int m=l+r>>1; if(L<=m) update(L,R,c,lson); if(R>m) update(L,R,c,rson); pushup(l,r,rt); } void init(){ tot=m=0; memset(cnt,0,sizeof cnt); memset(sum,0,sizeof sum); } int main(){ int T=0,n; while(scanf("%d",&n) && n){ init(); for(int i=1;i<=n;i++){ double x1,y1,x2,y2; scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2); segs[tot]=Seg(x1,x2,y1,1);data[tot++]=x1; segs[tot]=Seg(x1,x2,y2,-1);data[tot++]=x2; } sort(segs,segs+tot); sort(data,data+tot); m=unique(data,data+tot)-data; double ret=0; for(int i=0;i<tot;i++){ int posl=lower_bound(data,data+m,segs[i].l)-data; int posr=lower_bound(data,data+m,segs[i].r)-data-1; if(posl<=posr) update(posl,posr,segs[i].d,0,m,1);//把這條邊更新到線段樹中 ret+=sum[1]*(segs[i+1].h-segs[i].h); } printf("Test case #%d\nTotal explored area: %.2lf\n\n",++T , ret); } return 0; }