求覆盖三次及其以上的长方体体积并。
这题跟 http://wenku.baidu.com/view/d6f309eb81c758f5f61f6722.html 这里讲的长方体体积并并不一样。
因为本题Z坐标范围非常小,所以可以离散化Z坐标,枚举每个体积块。
对每一个体积块:用底面积*高求其体积。底面积直接用“线段树求长方形面积并”来得到即可。
对于覆盖次数,pushUp的时候:
1.满足 当前覆盖次数大于等于3的,直接求线段长。
2.小于3的,由 左右儿子覆盖次数=3 - 当前覆盖次数 的两个儿子更新上来得到。
#include <cstdio> #include <cstdlib> #include <cstring> #include <algorithm> using namespace std; #define lson l, m, rt << 1 #define rson m + 1, r, rt << 1 | 1 #define lc rt << 1 #define rc rt << 1 | 1 #define LL long long int const int MAXN = 2010; struct cube { int x1, y1, z1; int x2, y2, z2; void readCube() { scanf( "%d%d%d", &x1, &y1, &z1 ); scanf( "%d%d%d", &x2, &y2, &z2 ); return; } }cb[MAXN]; struct Line { int s; //sao ru sao chu int x; int y1, y2; Line() {} Line( int s, int x, int y1, int y2 ): s(s), x(x), y1(y1), y2(y2) { } void showLine() { printf("s=%d x=%d y1=%d y2=%d ", s, x, y1, y2 ); return; } }; struct node { int cnt; int len[3]; }; int N; node Tr[ MAXN << 3 ]; Line L[ MAXN << 3 ]; int Z[MAXN << 1]; int Y[MAXN << 2]; //li san hua int cntZ, cntY; bool cmp( const Line& a, const Line &b ) { if ( a.x != b.x ) return a.x < b.x; return a.s > b.s; } void build( int l, int r, int rt ) { for ( int i = 0; i < 3; ++i ) Tr[rt].len[i] = 0; Tr[rt].cnt = 0; if ( l == r ) return; int m = ( l + r ) >> 1; build( lson ); build( rson ); return; } void PushUp( int rt, int l, int r ) { //len0 if ( Tr[rt].cnt > 0 ) Tr[rt].len[0] = Y[r+1] - Y[l]; else Tr[rt].len[0] = Tr[lc].len[0] + Tr[rc].len[0]; //len1 if ( Tr[rt].cnt > 1 ) Tr[rt].len[1] = Y[r+1] - Y[l]; else if ( Tr[rt].cnt == 1 ) Tr[rt].len[1] = Tr[lc].len[0] + Tr[rc].len[0]; else Tr[rt].len[1] = Tr[lc].len[1] + Tr[rc].len[1]; //len2 if ( Tr[rt].cnt > 2 ) Tr[rt].len[2] = Y[r+1] - Y[l]; else if ( Tr[rt].cnt == 2 ) Tr[rt].len[2] = Tr[lc].len[0] + Tr[rc].len[0]; else if ( Tr[rt].cnt == 1 ) Tr[rt].len[2] = Tr[lc].len[1] + Tr[rc].len[1]; else Tr[rt].len[2] = Tr[lc].len[2] + Tr[rc].len[2]; return; } void Update( int L, int R, int v, int l, int r, int rt ) { if ( L <= l && r <= R ) { Tr[rt].cnt += v; PushUp( rt, l, r ); return; } if ( l == r ) return; int m = ( l + r ) >> 1; if ( L <= m ) Update( L, R, v, lson ); if ( R > m ) Update( L, R, v, rson ); PushUp( rt, l, r ); return; } int main() { int T, cas = 0; scanf( "%d", &T ); while ( T-- ) { scanf( "%d", &N ); cntZ = 0; cntY = 0; for ( int i = 0; i < N; ++i ) { cb[i].readCube(); Z[cntZ++] = cb[i].z1; Z[cntZ++] = cb[i].z2; Y[cntY++] = cb[i].y1; Y[cntY++] = cb[i].y2; } sort( Z, Z + cntZ ); sort( Y, Y + cntY ); cntZ = unique( Z, Z + cntZ ) - Z; cntY = unique( Y, Y + cntY ) - Y; LL ans = 0; for ( int i = 0; i < cntZ - 1; ++i ) { int cntL = 0; for ( int j = 0; j < N; ++j ) { if ( cb[j].z1 <= Z[i] && cb[j].z2 >= Z[i + 1] ) { L[cntL++] = Line( 1, cb[j].x1, cb[j].y1, cb[j].y2 ); L[cntL++] = Line(-1, cb[j].x2, cb[j].y1, cb[j].y2 ); } } sort( L, L + cntL, cmp ); build( 0, cntY - 1, 1 ); for ( int k = 0; k < cntL; ++k ) { if ( k ) ans += (LL)( L[k].x-L[k-1].x )*Tr[1].len[2]*( Z[i+1]-Z[i] ); int a = lower_bound( Y, Y + cntY, L[k].y1 ) - Y; int b = lower_bound( Y, Y + cntY, L[k].y2 ) - Y - 1; //这里一定要减1!!!!!! Update( a, b, L[k].s, 0, cntY - 1, 1 ); } } printf( "Case %d: %lld ", ++cas, ans ); } return 0; }
之前一直调试不出结果,是因为点树和线段树没分清楚,就是线段树节点中存的是一个点,还是一个单位长度倍数的线段。
对于二分得到a,b值,b值需要-1,而pushUp的时候r值需要+1这里并不是很理解。