HDU_3642 Get The Treasury 线段树

http://acm.hdu.edu.cn/showproblem.php?pid=3642

题意:

给你N个立方体,求空间中被不同的立方体覆盖至少3次的体积。

思路:

这个题目是一个三维空间的体积交的题,和HDU1255的面积交是差不多的,本题可以先将Z轴离散化,然后对于每个Z轴上的区间,只要求出此时的合法面积然后再乘以Z轴上的高度就可以了。每次求合法面积的时候只要用二维的矩形面积交,然后求出至少覆盖三次的面积就可以了。

代码:

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<math.h>
#define LL(a) ( (a)<<1 )
#define RR(a) ( (a)<<1|1 )
#define STOP system("pause")
#define MAX(a , b) ( (a)>(b)?(a):(b) )
#define MIN(a , b) ( (a)>(b)?(b):(a) )

using namespace std;

const int MAXN = 5050 ;

struct point{
    int x, y, z ;
    point(){}
    point(int a, int b, int c)
    : x(a) , y(b) , z(c){}
};

struct Node{
    point p1,p2;
    void init(int a, int b ,int c ,int a1, int b1, int c1){
        p1 = point(a ,b , c ) ;
        p2 = point(a1 , b1 , c1 );
    }
}p[MAXN] ;

struct Seg{
    int l ,r , h , s ;
    Seg(){}
    Seg(int a, int b , int c , int d )
    :l(a), r(b) , h(c) , s(d) {}
    bool operator< (const Seg& cmp )const {
        return h < cmp.h ;
    }
}pp[MAXN] ;

int N ;
int X[MAXN] ;
int col[MAXN<<2] ;
int sum1[MAXN<<2] , sum2[MAXN<<2] , sum3[MAXN<<2] ;
int Z[MAXN] ;

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

void pushup(int l ,int r , int idx){
    int ls = LL(idx) , rs = RR(idx) ;
    if( col[idx] >= 3 ){
        sum1[idx] = sum2[idx] = 0 ;
        sum3[idx] = X[r+1] - X[l] ;
    }
    else if( col[idx] == 2 ){
        sum1[idx] = 0 ;
        if(l == r)  sum3[idx] = 0 ;
        else    sum3[idx] = sum3[ls] + sum3[rs] + sum2[ls] + sum2[rs] + sum1[ls] + sum1[rs] ;
        sum2[idx] = X[r+1] - X[l] - sum3[idx] ;
    }
    else if( col[idx] == 1){
        if(l == r){
            sum2[idx] = sum3[idx] = 0 ;
        }
        else{
            sum3[idx] = sum3[ls] + sum3[rs] + sum2[ls] + sum2[rs] ;
            sum2[idx] = sum1[ls] + sum1[rs] ;
        }
        sum1[idx] = X[r+1] - X[l] - sum2[idx] - sum3[idx] ;
    }
    else{
        if(l == r ) sum3[idx] = sum2[idx] = sum1[idx] = 0 ;
        else{
            sum1[idx] = sum1[ls] + sum1[rs] ;
            sum2[idx] = sum2[ls] + sum2[rs] ;
            sum3[idx] = sum3[ls] + sum3[rs] ;
        }
    }
}

void update(int l ,int r, int idx, int a,  int b, int v ){
    if(l==a && r==b ){
        col[idx] += v ;
        pushup(l , r , idx );
        return ;
    }

    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 );
    }
    pushup(l, r ,idx);
}

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

int nn ;
void solve(){
    int m , n ,tot;
    __int64 res = 0 ;
    for(int i=0;i<nn;i++) {
        int c1 = Z[i] , c2 = Z[i+1] ;
        m = 0 ; tot = 0 ;
        for(int i=0;i<N;i++){
            int x1 = p[i].p1.x ;
            int x2 = p[i].p2.x ;
            int y1 = p[i].p1.y ;
            int y2 = p[i].p2.y ;
            int z1 = p[i].p1.z ;
            int z2 = p[i].p2.z ;
            if( z1<=c1 && z2>=c2 ){
                X[m] = x1  ;
                pp[m++] = Seg(x1 , x2 , y1 , 1 );
                X[m] = x2 ;
                pp[m++] = Seg(x1 , x2 , y2 , -1 );
            }
        }
        sort(X , X + m);
        sort(pp , pp + m );
        n = 1 ;
        for(int i=1;i<m;i++)
            if( X[i] != X[i-1] )
                X[n++] = X[i] ;
        n-- ;
        build(0 , n , 1 );
        __int64 ans = 0 ;
        for(int i=0;i<m-1;i++){
            int s = find(pp[i].l , 0 , n ) ;
            int e = find(pp[i].r , 0 , n ) - 1 ;
            if(s <= e){
                update(0, n , 1 , s ,e , pp[i].s );
            }
            ans += (__int64)(sum3[1])*(__int64)( pp[i+1].h - pp[i].h ) ;
        }
        res += ans*(__int64)(c2-c1);
    }
    printf("%I64d\n",res);
}

int main(){
    int t , tt ;
    int a , b ,c , a1, b1, c1 ;
    scanf("%d",&tt);
    for(t = 0 ; t<tt ; t ++){
        scanf("%d",&N);
        int m = 0 ;
        for(int i=0;i<N;i++){
            scanf("%d%d%d%d%d%d",&a,&b,&c,&a1,&b1,&c1);
            p[i].init(a,b,c,a1,b1,c1);
            Z[m++] = c ; Z[m++] = c1 ;  //离散化Z轴
        }
        sort(Z, Z+m );
        nn = 1 ;
        for(int i=1;i<m;i++)            //压缩
            if( Z[i] != Z[i-1] ) Z[nn++] = Z[i] ;
        nn-- ;
        printf("Case %d: ",t+1);
        solve() ;
    }
    return 0 ;
}

你可能感兴趣的:(HDU_3642 Get The Treasury 线段树)