1. 程式人生 > >【HDU1542】Atlantis

【HDU1542】Atlantis

線段樹 上下 return 部分 img sum UC != view

題意

給出n個矩形的左下角和右上角的坐標,計算總的面積(相交部分只算一次)。

分析

線段樹掃描線的模板題。

將每個矩形都拆成上下兩條線段,然後從下網上掃,當遇到底邊時就加上這個區間,遇到頂邊時,就減去這個區間。這些都很好理解,但是有一個點我感覺很難受!對於普通線段樹,先將區間[1,2]+1,再更新區間[2,3]+1的話,2這個點的值應該是2。但是掃描線來說,2應該是1。因為[1,3]是一條線。我們的解決辦法是,在線段樹[L,R]的區間內儲存[L,R+1]的值

技術分享圖片
 1 #include <cstdio>
 2 #include <cstring>
 3
#include <iostream> 4 #include <algorithm> 5 6 using namespace std; 7 const int maxn=200; 8 struct Node{ 9 double l,r,h; 10 int state; 11 bool operator <(const Node & rhs)const{ 12 return h<rhs.h; 13 } 14 Node (){} 15 Node (double
l,double r,double h,int state):l(l),r(r),h(h),state(state){} 16 }node[maxn]; 17 double v[maxn]; 18 int n,kase; 19 double x1,y1,x2,y2,ans; 20 double sumv[4*maxn]; 21 int cover[4*maxn]; 22 23 void maintain(int o,int L,int R){ 24 if(cover[o]) 25 sumv[o]=v[R+1]-v[L]; 26 else if
(L==R) 27 sumv[o]=0; 28 else 29 sumv[o]=sumv[2*o]+sumv[2*o+1]; 30 } 31 int ql,qr,vv; 32 void update(int o,int L,int R){ 33 if(ql<=L&&qr>=R){ 34 cover[o]+=vv; 35 maintain(o,L,R); 36 return ; 37 } 38 int M=L+(R-L)/2; 39 if(ql<=M)update(2*o,L,M); 40 if(qr>M)update(2*o+1,M+1,R); 41 maintain(o,L,R); 42 } 43 int main(){ 44 kase=0; 45 while(scanf("%d",&n)!=EOF&&n){ 46 int sz=0; 47 ++kase; 48 for(int i=1;i<=n;i++){ 49 scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2); 50 node[++sz].l=x1,node[sz].r=x2,node[sz].h=y1,node[sz].state=1,v[sz]=x1; 51 node[++sz].l=x1,node[sz].r=x2,node[sz].h=y2,node[sz].state=-1,v[sz]=x2; 52 } 53 sort(node+1,node+1+sz); 54 sort(v+1,v+1+sz); 55 int N=unique(v+1,v+1+sz)-v-1; 56 memset(sumv,0,sizeof(sumv)); 57 memset(cover,0,sizeof(cover)); 58 ans=0; 59 for(int i=1;i<sz;i++){ 60 ql=lower_bound(v+1,v+1+N,node[i].l)-v,qr=lower_bound(v+1,v+1+N,node[i].r)-v-1,vv=node[i].state; 61 update(1,1,N); 62 ans+=sumv[1]*(node[i+1].h-node[i].h); 63 } 64 printf("Test case #%d\n",kase); 65 printf("Total explored area: %.2f\n",ans); 66 printf("\n"); 67 } 68 return 0; 69 }
View Code

【HDU1542】Atlantis