hdu 1542 Atlantis

求矩形的面积之和。

线段树+离散话+扫描线

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstdlib>
 4 #include<cstring>
 5 #include<string>
 6 #include<queue>
 7 #include<algorithm>
 8 #include<map>
 9 #include<iomanip>
10 #define INF 99999999
11 using namespace std;
12 
13 const int MAX=200+10;
14 int mark[MAX<<2];//记录某个区间的下底边个数
15 double sum[MAX<<2];//记录某个区间的下底边总长度
16 double lisan[MAX];//对x进行离散化,否则x为浮点数且很大无法进行线段树
17 
18 //以横坐标作为线段(区间),对横坐标线段进行扫描
19 //扫描的作用是每次更新下底边总长度和下底边个数,增加新面积
20 struct seg{//线段
21     double l,r,h;
22     int d;
23     seg(){}
24     seg(double x1,double x2,double H,int c):l(x1),r(x2),h(H),d(c){}
25     bool operator<(const seg &a)const{
26         return h<a.h;
27     }
28 }s[MAX];
29 
30 void Upfather(int n,int left,int right){
31     if(mark[n])sum[n]=lisan[right+1]-lisan[left];//表示该区间整个线段长度可以作为底边
32     else if(left == right)sum[n]=0;//叶子结点则底边长度为0(区间内线段长度为0)
33     else sum[n]=sum[n<<1]+sum[n<<1|1];
34 }
35 
36 void Update(int L,int R,int d,int n,int left,int right){
37     if(L<=left && right<=R){//该区间是当前扫描线段的一部分,则该区间下底边总长以及上下底边个数差更新
38         mark[n]+=d;//更新底边相差差个数
39         Upfather(n,left,right);//更新底边长
40         return;
41     }
42     int mid=left+right>>1;
43     if(L<=mid)Update(L,R,d,n<<1,left,mid);
44     if(R>mid)Update(L,R,d,n<<1|1,mid+1,right);
45     Upfather(n,left,right);
46 }
47 
48 int search(double key,double* x,int n){
49     int left=0,right=n-1;
50     while(left<=right){
51         int mid=left+right>>1;
52         if(x[mid] == key)return mid;
53         if(x[mid]>key)right=mid-1;
54         else left=mid+1;
55     }
56     return -1;
57 }
58 
59 int main(){
60     int n,num=0;
61     double x1,x2,y1,y2;
62     while(cin>>n,n){
63         int k=0;
64         for(int i=0;i<n;++i){
65             cin>>x1>>y1>>x2>>y2;
66             lisan[k]=x1;
67             s[k++]=seg(x1,x2,y1,1);
68             lisan[k]=x2;
69             s[k++]=seg(x1,x2,y2,-1);
70         }
71         sort(lisan,lisan+k);
72         sort(s,s+k);
73         int m=1;
74         for(int i=1;i<k;++i)//去重复端点
75             if(lisan[i] != lisan[i-1])lisan[m++]=lisan[i];
76         double ans=0;
77         //memset(mark,0,sizeof mark);
78         //memset(sum,0,sizeof sum);//如果下面是i<k-1,则要初始化,因为如果对第k-1条,线段扫描时会使得mark,sum为0才不用初始化的
79         for(int i=0;i<k;++i){//扫描线段
80             int L=search(s[i].l,lisan,m);
81             int R=search(s[i].r,lisan,m)-1;
82             Update(L,R,s[i].d,1,0,m-1);//扫描线段时更新底边长度和底边相差个数
83             ans+=sum[1]*(s[i+1].h-s[i].h);//新增加面积
84         }
85         printf("Test case #%d\nTotal explored area: %.2lf\n\n",++num,ans);
86     }
87     return 0;
88 }

 

posted on 2015-04-30 20:58  tsw123  阅读(103)  评论(0编辑  收藏  举报

导航