题目描述
A君近日为准备省队选拔,特意进行了数据结构的专项训练。训练过程中就遇到了“矩形面积并”这道经典问题,即:给出 NN 个各边与坐标轴平行(垂直)的矩形,求矩形覆盖的面积之和。A君按纵坐标建立线段树后按横坐标扫描计算,轻易 AC 了这道题,时间复杂度为 O(N\log N)O(NlogN)。
为了强化训练,A君将问题推广到三维空间中,即:给出 NN 个各棱与坐标轴平行(垂直)的立方体,求立方体覆盖的体积之和。为了简化问题,令立方体均退化为正立方体,用四元组 (x, y, z, r)(x,y,z,r) 表示一个立方体,其中 x, y, zx,y,z 为立方体的中心点坐标,rr 为中心点到立方体各个面的距离(即立方体高的一半)。
这次可难住了A君,只好请你——未来的金牌——来帮助他了。
输入格式
第一行是一个正整数 NN。
以下 NN 行每行四个整数 x, y, z, rx,y,z,r。
输出格式
输出覆盖的总体积。
输入输出样例
3 0 0 0 3 1 –1 0 1 19 3 5 6
1944
说明/提示
N \leq 100, -1000 \leq x,y,z \leq 1000, r \leq 200N≤100,−1000≤x,y,z≤1000,r≤200
-------------------------------------------------------------------------------------------------------------------------
这题的数据范围暗示了一切。
没错,就是一道大暴力
那么就构想一下怎么暴力吧(虽说各位大佬已经切了这道题)
既然是三维空间,那么就可以考虑转化为二维情况,发现只要暴力枚举一下二维平面的坐标点,再另外处理一下第三维就行了。(卡常还是比较轻松的)
详见代码
#include<bits/stdc++.h>
#define LL long long
#define Maxn 110
using namespace std;
struct Sq{
int xb,xe,yb,ye,zb,ze;
}a[Maxn];
struct Node{
int b,e;
}c[Maxn];
int ans;
inline int read(){
int x = 0,f = 1;char ch = getchar();
while (!isdigit(ch)){if (ch == '-') f = -1; ch = getchar(); }
while (isdigit(ch)){x = (x << 3) + (x << 1) + ch - 48; ch = getchar(); }
return (f==1)?x:-x;
}
inline bool cmp(Sq x,Sq y){
if (x.zb != y.zb) return x.zb < y.zb;
return x.ze < y.ze;
}
int main(){
freopen("cover.in","r",stdin);
freopen("cover.out","w",stdout);
int n = read();
int bx = 1e9, by = 1e9, ex = -1e9, ey = -1e9;//优化一下暴力,记开始位置和结束位置,然后枚举一下
for (int i = 1; i <= n; i++){
int x = read() + 1200, y = read() + 1200, z = read() + 1200, d = read();
a[i].xb = x - d + 1, a[i].xe = x + d;
bx = min(a[i].xb, bx), ex = max(a[i].xe, ex);
a[i].yb = y - d + 1, a[i].ye = y + d;
by = min(a[i].yb, by), ey = max(a[i].ye, ey);
a[i].zb = z - d + 1, a[i].ze = z + d;
}
sort(a + 1, a + n + 1, cmp);//按照z轴排序,优先考虑开始位置下面的立方体,这样统计区间时方便一些
for (int i = bx; i <= ex; i++){
for (int j = by; j <= ey; j++){
int cnt=0;
for (int k = 1; k <= n; k++)
if (i >= a[k].xb && i <= a[k].xe && j >= a[k].yb && j <= a[k].ye)
if (c[cnt].e < a[k].zb) c[++cnt] = (Node){a[k].zb, a[k].ze};
else c[cnt].e = max(a[k].ze, c[cnt].e);
for (int k = 1; k <= cnt; k++) ans += c[k].e - c[k].b + 1;//统计区间
}
}
printf("%d\n",ans);
return 0;
}
%%Modest XXX:\ 这么丑的码风,我不想看(又被diss了)