HDU_1542 Atlatis線分樹

3981 ワード

http://acm.hdu.edu.cn/showproblem.php?pid=1542
件名:
N個の長方形の面積を求めます. 
考え方:
線分樹+走査線+離散化.まず、すべての長方形を四辺に開いて、水平方向と垂直方向に領域を切断して、いわゆる「メタ線分」を形成して、線分樹で解いてもいいです.
コード:
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<stdlib.h>
#include<math.h>
using namespace std;
#define LL(a) ( (a)<<1 )
#define RR(a) ( (a)<<1|1 )
#define eps (1e-6)

const int MAXN = 110<<1 ;
int N , NN;
struct Seg{
    double l, r , h ;
    int s ;
    Seg(){}
    Seg(double a,  double b, double c , double ss)
    :l(a), r(b) , h(c) ,s(ss){}
    bool operator< ( const Seg& seg) const {
        return h > seg.h ;
    }
}line[MAXN] ;

int col[MAXN<<2] ;
int set[MAXN<<2] ;
double sum[MAXN<<2] ;
double X[MAXN<<2] ;
double len[MAXN<<2] ;
double s_len[MAXN<<2] ;

void build(int l ,int r ,int idx){
    col[idx] = 0 ;
    set[idx] = 0 ;
    sum[idx] =  0;
    if(l == r)  return ;
    int mid = (l + r) >> 1 ;
    build(l , mid , LL(idx));
    build(mid+1,r , RR(idx));
}

int find(double d,int l , int r ){
    int mid ;
    while(l < r){
        mid = (l + r) >> 1 ;
        if( X[mid] < d )
            l = mid + 1 ;
        else
            r = mid ;
    }
    return l + 1 ;
}

void down(int l ,int r, int idx){
    int mid = (l + r) >> 1 ;
    if( set[idx] ){
        col[ LL(idx) ] = col[idx] ;
        set[ LL(idx) ] = 1 ;
        if( col[ LL(idx) ] == 0 )   sum[ LL(idx) ] = 0 ;
        else                        sum[ LL(idx) ] = s_len[mid] - s_len[l-1] ;
        col[ RR(idx) ] = col[idx] ;
        set[ RR(idx) ] = 1 ;
        if( col[ RR(idx) ] == 0 )   sum[ RR(idx) ] = 0 ;
        else                        sum[ RR(idx) ] = s_len[r] - s_len[mid] ;
        set[idx] = 0 ;
    }
}

void up(int l , int r,  int idx ){
    if( col[ LL(idx) ] == col[ RR(idx) ] )
        col[idx] = col[ LL(idx) ] ;
    else
        col[idx] = -1 ;
    sum[idx] =  sum[ LL(idx) ] + sum[ RR(idx) ] ;
}

void update(int l ,int r, int idx, int a , int b  , int v){
    if(l==a && r==b && col[idx] != -1 ){
        col[idx] += v ;
        set[idx] = 1 ;
        if( col[idx] == 0 ) sum[idx] = 0 ;
        else                sum[idx] =  s_len[r] - s_len[l-1] ;
        return ;
    }
    down(l, r, idx );
    int mid = (l + r) >> 1 ;
    if( b<=mid )    update(l , mid , LL(idx) , a , b , v );
    else if( mid<a )    update(mid+1 , r, RR(idx) , a, b, v );
    else{
        update(l,  mid , LL(idx) ,a ,mid , v);
        update(mid+1 , r , RR(idx) , mid+1, b , v );
    }
    up(l, r, idx) ;
}

int main(){
    double a, b, c , d ;
    int cas = 0;
    while( scanf("%d",&N) && N ){
        NN = N<<1 ;
        for(int i=0;i<N;i++){
            scanf("%lf%lf%lf%lf",&a,&b,&c,&d);
            X[i<<1] = a ;   X[i<<1|1] = c ;
            line[i<<1] = Seg(a , c , b , -1 );
            line[i<<1|1] = Seg(a , c ,d  ,1 );
        }
        sort(X , X+NN);
        sort(line , line+NN) ;
        int k = 0 ;
        X[k++] = X[0] ;
        for(int i=1;i<NN;i++){
            if( fabs( X[i] - X[i-1] ) <= eps )  continue ;
            X[k++] = X[i] ;
        }
        s_len[0] = 0;
        for(int i=0;i<k;i++){
            len[i+1] = X[i+1] - X[i] ;
            s_len[i+1] = s_len[i] + len[i+1] ;
        }
        k-- ;
        double dis = line[0].h ;
        build(1, NN , 1);
        double ans = 0 ;
        for(int i=0;i<NN-1;i++){
            int s = find( line[i].l , 0 , k ) ;
            int e = find( line[i].r , 0 , k ) ;
            update(1, NN , 1 , s ,e-1, line[i].s );
            double dis = line[i].h - line[i+1].h ;
            ans += dis*sum[1] ;
        }
        printf("Test case #%d
",++cas); printf("Total explored area: %.2lf

",ans); } return 0 ; }