思路:线段树扫描线模板。
扫描线求矩形并面积大致思路:
从下往上扫的话 ,需要先存下来矩形的上下边,按照y的大小排序,记录每条线段的左右端点l , r 以及高度 y , 下边对应区域就加1,上边减1,每次拿这条线段到下条线段的距离 * 区域总长度累加就是并的总面积。
过程大致就是下面这样,从下往上,遇到上下边就更新,求和。
本来看完题想着复习重敲下代码的,但是这题我二分找位置的时候用函数调用ME,直接写就AC,一直找不到ME的原因导致我弄了一晚上,想吐早知道不写了。。。。
Code:
#include <bits/stdc++.h>
using namespace std ;
const int AX = 222 ;
struct Node{
double l , r , y ;
int cov ;
Node(){};
Node( double l , double r , double y , int cov ):l(l),r(r),y(y),cov(cov){}
bool operator < ( const Node &ch )const{
return y < ch.y ;
}
}line[AX];
vector<double> X;
double sum[AX<<2] ;
int mark[AX<<2] ;
int getId( int x ){
return lower_bound( X.begin() , X.end() , x ) - X.begin() + 1 ;
}
void pushUp( int rt , int l , int r ){
if( mark[rt] ) sum[rt] = X[r] - X[l-1] ; // r - 1 + 1
else if( l == r ) sum[rt] = 0 ;
else sum[rt] = sum[rt<<1] + sum[rt<<1|1];
}
void update( int L , int R , int cov , int l , int r , int rt ){
if( L <= l && R >= r ){
mark[rt] += cov ;
pushUp( rt , l , r ) ;
return ;
}
int mid = ( l + r ) >> 1 ;
if( L <= mid ) update( L , R , cov , l , mid , rt << 1 ) ;
if( R > mid ) update( L , R , cov , mid + 1 , r , rt << 1 | 1 ) ;
pushUp( rt , l , r ) ;
}
int main(){
int n ;
int Case = 0 ;
while( scanf("%d",&n) && n ){
X.clear() ;
double x1 , y1 , x2 , y2 ;
int num = 0 ;
while( n-- ){
scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
X.push_back(x1) ;
line[num++] = Node( x1 , x2 , y1 , 1 ) ;
X.push_back(x2) ;
line[num++] = Node( x1 , x2 , y2 , -1 ) ;
}
sort( line , line + num ) ;
sort( X.begin() , X.end() ) ;
X.erase( unique( X.begin() , X.end() ) , X.end() ) ;
int len = X.size() ;
double res = 0 ;
for( int i = 0 ; i < num ; i ++ ){
int l = lower_bound( X.begin() , X.end() , line[i].l ) - X.begin() + 1;
int r = lower_bound( X.begin() , X.end() , line[i].r ) - X.begin() + 1 - 1 ;
/*int l = getId( line[i].l ) ;
int r = getId( line[i].r ) - 1 ; */
update( l , r , line[i].cov , 1 , len , 1 ) ;
res += sum[1] * ( line[i+1].y - line[i].y ) ;
}
printf("Test case #%d\n",++Case);
printf("Total explored area: %.2lf\n",res);
printf("\n");
}
return 0 ;
}