题解 [SDOI2008]立方体覆盖
题目描述
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了)