线段树。
给你N个方体区域,求覆盖三次以上(包括三次)的区域的体积。
在sha崽的线段树扫描线分类。。。开始纠结了,这个三维咋转化成一维的呢。。给的坐标是蛮小的。有人说是枚举z坐标。。想了想。
因为之前的矩形面积交那个题,印象不是太深,又重新把那个题给看了。在那个题的基础上,改成了覆盖三次以上的求面积的。
然后就很显然了,离散化z坐标,然后一层一层向上扫描,每一层算覆盖>=3次的面积(用矩形面积交>=3的那个),然后乘以这一层的高度,就是这一层覆盖>=3次的体积。
开始我是直接循环-500到500的z的,后来想了想,没必要,用离散化后的z坐标即可。
然后当前层的话,只要这个方体覆盖了当前层,就加扫描线,和普通二维扫描线一样。
注意用__int64。嘻嘻,1218ms,hdu这题rank3~
我中间更新的过程很。。。纠结。改了点,WA了。如果不用memset初始化所有节点(memset很很费时间!!因为节点数组一般都开很大,而且每组数据都需要初始化),那么,用的时候,一定不要用叶子节点的下一层的点,因为下一层的没有初始化,可能保留的是上一组数据的内容,很有可能出现问题。
#include <set> #include <map> #include <queue> #include <stack> #include <math.h> #include <stdio.h> #include <stdlib.h> #include <iostream> #include <limits.h> #include <string.h> #include <string> #include <algorithm> #define MID(x,y) ( ( x + y ) >> 1 ) #define L(x) ( x << 1 ) #define R(x) ( x << 1 | 1 ) #define FOR(i,s,t) for(int i=(s); i<(t); i++) #define BUG puts("here!!!") #define STOP system("pause") #define file_r(x) freopen(x, "r", stdin) #define file_w(x) freopen(x, "w", stdout) using namespace std; const int MAX = 2010; typedef __int64 LL; int z[MAX], y[MAX], cntz, cnty; struct point{ // 三维点的定义 int x, y, z; void get() { scanf("%d%d%d", &x, &y, &z); } }; struct Tnode{ // 一维线段树 int l,r,cover, once, twice, len; int mid() { return MID(l,r);} bool in(int ll,int rr) { return l >= ll && r <= rr; } void lr(int ll,int rr){ l = ll; r = rr;} }; struct box{ // 长方体定义 point a, b; }; struct Sline{int x,y1,y2,flag;}; // 扫描线定义 Tnode node[MAX<<2]; box bo[MAX]; Sline l[MAX]; void add_line(int x1,int y1,int x2,int y2,int &cnt) { l[cnt].x = x1; l[cnt].y1 = y1; l[cnt].y2 = y2; l[cnt++].flag = 1; l[cnt].x = x2; l[cnt].y1 = y1; l[cnt].y2 = y2; l[cnt++].flag = -1; } bool cmp(Sline a, Sline b) { if( a.x == b.x ) return a.flag > b.flag; return a.x < b.x; } void Build(int t,int l,int r) { node[t].lr(l, r); node[t].cover = node[t].once = node[t].twice = node[t].len = 0; if( node[t].l == node[t].r - 1 ) return ; int mid = MID(l,r); Build(L(t),l,mid); Build(R(t),mid,r); } void Updata_len(int t) { if( node[t].cover >= 3 ) { node[t].once = node[t].twice = 0; node[t].len = y[node[t].r] - y[node[t].l]; return ; } if( node[t].cover == 2 ) { if( node[t].l == node[t].r - 1 ) { node[t].twice = y[node[t].r] - y[node[t].l]; node[t].len = node[t].once = 0; } else { node[t].once = 0; node[t].len = node[R(t)].len + node[L(t)].len + node[R(t)].once + node[L(t)].once + node[L(t)].twice + node[R(t)].twice; node[t].twice = y[node[t].r] - y[node[t].l] - node[t].len; } return ; } if( node[t].cover == 1 ) { if( node[t].l == node[t].r - 1 ) { node[t].len = node[t].twice = 0; node[t].once = y[node[t].r] - y[node[t].l]; } else { node[t].len = node[R(t)].len + node[L(t)].len + node[L(t)].twice + node[R(t)].twice; node[t].twice = node[L(t)].once + node[R(t)].once; node[t].once = y[node[t].r] - y[node[t].l] - node[t].len - node[t].twice; } return ; } if( node[t].cover == 0 ) { if( node[t].l == node[t].r - 1 ) node[t].len = node[t].once = node[t].twice = 0; else { node[t].len = node[R(t)].len + node[L(t)].len; node[t].once = node[R(t)].once + node[L(t)].once; node[t].twice = node[R(t)].twice + node[L(t)].twice; } return ; } } void Updata(int t, Sline p) { if( y[node[t].l] >= p.y1 && y[node[t].r] <= p.y2 ) { node[t].cover += p.flag; Updata_len(t); return ; } if( node[t].l == node[t].r - 1 ) return ; int mid = node[t].mid(); if( p.y1 < y[mid] ) Updata(L(t), p); if( p.y2 > y[mid] ) Updata(R(t), p); Updata_len(t); } LL solve(int n) { sort(y, y+cnty); sort(z, z+cntz); cnty = unique(y, y+cnty) - y; cntz = unique(z, z+cntz) - z; LL ans = 0; Build(1, 0, cnty-1); FOR(i, 0, cntz-1) { LL area = 0; int cnt = 0; FOR(k, 0, n) if( bo[k].a.z <= z[i] && bo[k].b.z > z[i] ) add_line(bo[k].a.x, bo[k].a.y, bo[k].b.x, bo[k].b.y, cnt); sort(l, l+cnt, cmp); Updata(1, l[0]); FOR(k, 1, cnt) { area += node[1].len *1ll* (l[k].x - l[k-1].x); // 注意这点,不乘1ll会WA。。 Updata(1, l[k]); } ans += area * (z[i+1] - z[i]); } return ans; } int main() { int ncases, ind = 1, n; scanf("%d", &ncases); while( ncases-- ) { scanf("%d", &n); cntz = cnty = 0; FOR(i, 0, n) { bo[i].a.get(); bo[i].b.get(); y[cnty++] = bo[i].a.y; // 离散化 y 坐标 y[cnty++] = bo[i].b.y; z[cntz++] = bo[i].a.z; // 离散化 z 坐标 z[cntz++] = bo[i].b.z; } LL ans = solve( n ); printf("Case %d: %I64d\n", ind++, ans); } return 0; }