题意:
求相交三次及以上的立方体体积。
思路:
由于z 最多只有1000层, 故我们可以直接对每一层求一次面积并。 但是求层数的时候有一个特别要注意的地方, 比如z包含 3 4 5这3层,算的时候我们求的是3层,实际上我们求体积只用求2层即可。故判断一下就行。这样若果只有一层 的话就不会算进去,因为一层构不成体积。 其他的就和基本的扫描线类似了。
code:
#include <cstdio>
#include <iostream>
#include <algorithm>
typedef long long ll;
using namespace std;
const int N = 2e4 + 5, M = 1005;
struct Line {
int st;
double s, e, x, z1, z2; //z1、z2记录这条线的范围
bool operator < (const Line & w) const {
return x < w.x;
}
} line[N];
struct Node {
int cnt, len1, len2, len3;
} tr[N << 2];
int t, n, cnt, m, x1, x2, y1, y2, z1, z2, fy[N];
int find(int y) {
return lower_bound(fy + 1, fy + 1 + cnt, y) - fy;
}
void pushup(int id, int l, int r) {
if (tr[id].cnt){ // 代表id这个区间被覆盖了
tr[id].len1 = fy[r + 1] - fy[l]; //因为一个点代表的是一个区间 那r这个点的区间 就是[fy[r], fy[r + 1]]这段长度
} else if (l != r){ //如果这整个区间没有被包含 那么就由儿子区间组成
tr[id].len1 = tr[id << 1].len1 + tr[id << 1 | 1].len1;
} else tr[id].len1 = 0; //叶子结点
//当cnt >= 2的时候
if (tr[id].cnt >= 2) {
tr[id].len2 = fy[r + 1] - fy[l];
} else if (l != r && tr[id].cnt == 1) { //当cnt == 1的时候 子区间若被包含了一次那么加上父亲的一次就是2次了
tr[id].len2 = tr[id << 1].len1 + tr[id << 1 | 1].len1;
} else if (l != r){ //这种情况若不是根节点 那么便可以通过子节点的len2得来
tr[id].len2 = tr[id << 1].len2 + tr[id << 1 | 1].len2;
} else { //根节点 或者 不满足上面条件的都直接等于0
tr[id].len2 = 0;
}
//当cnt >= 3的时候
if (tr[id].cnt >= 3) {
tr[id].len3 = fy[r + 1] - fy[l];
} else if (l != r && tr[id].cnt == 2) {
tr[id].len3 = tr[id << 1].len1 + tr[id << 1 | 1].len1;
} else if (l != r && tr[id].cnt == 1) {
tr[id].len3 = tr[id << 1].len2 + tr[id << 1 | 1].len2;
} else if (l != r){
tr[id].len3 = tr[id << 1].len3 + tr[id << 1 | 1].len3;
} else {
tr[id].len3 = 0;
}
}
void build(int id, int l, int r) {
tr[id].cnt = tr[id].len1 = tr[id].len2 = tr[id].len3 = 0;
if (l == r) return;
int mid = (l + r) >> 1;
build(id << 1, l, mid);
build(id << 1 | 1, mid + 1, r);
}
void update(int id, int l, int r, int x, int y, int d) {
if (x <= l && r <= y) {
tr[id].cnt += d;
pushup(id, l, r);
return;
}
int mid = (l + r) >> 1;
if (x <= mid) update(id << 1, l, mid, x, y, d);
if (y > mid) update(id << 1 | 1, mid + 1, r, x, y, d);
pushup(id, l, r);
}
int main() {
scanf("%d", &t);
for (int ci = 1; ci <= t; ci++) {
scanf("%d", &n);
cnt = 0; //代表有多少个y点
for (int i = 1; i <= n; i++) {
scanf("%d%d%d%d%d%d", &x1, &y1, &z1, &x2, &y2, &z2);
line[++cnt].s = y1; line[cnt].e = y2, line[cnt].x = x1, line[cnt].z1 = z1, line[cnt].z2 = z2, line[cnt].st = 1, fy[cnt] = y1;
line[++cnt].s = y1; line[cnt].e = y2, line[cnt].x = x2, line[cnt].z1 = z1, line[cnt].z2 = z2, line[cnt].st = -1, fy[cnt] = y2;
}
//对y坐标进行离散化
sort(fy + 1, fy + 1 + cnt);
sort(line + 1, line + 1 + cnt);
m = cnt; //m代表有多少条线
cnt = unique(fy + 1, fy + 1 + cnt) - fy - 1; //代表离散化后y点的数量
ll ans = 0;
for (int z = -500; z <= 500; z++) {
build(1, 1, cnt - 1);
int lastx = 0;
for (int i = 1; i <= m; i++) {
if (line[i].z1 <= z && line[i].z2 > z) {
ans += (ll)tr[1].len3 * (line[i].x - lastx), lastx = line[i].x;
update(1, 1, cnt - 1, find(line[i].s), find(line[i].e) - 1, line[i].st);
}
}
}
printf("Case %d: %lld\n", ci, ans);
}
return 0;
}