题意:给你n个长方体,求至少相交三次的体积。
思路:1、z的数量较小,可以枚举z,对于两个z之间的夹层用二维扫描线
2、对于每个夹层,用二维扫描线求出相交至少三次的面积和,最后乘上一个△z(夹层的高度)即可
易错点:(我的天,第一次写完好多bug,都是处理不当导致的,以后一定要避免了!)
1、各个数组的下标要么全都是从0开始,要么都是从1开始,我比较喜欢从1开始。
2、unique函数使用的时候后面减掉的是(数组的首地址 + 1),lower_bound函数减掉的是数组的首地址;因为unique获得的是数组元素的个数,而lower_bound获得的是元素的下标。(这些一定要记清楚了,以后写代码可以加快速度)
代码:
1 #include <bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int maxn = 4010; 5 int z[maxn]; 6 int x[maxn]; 7 8 struct point 9 { 10 int x, y, z; 11 point(int a = 0, int b = 0, int c = 0) : x(a), y(b), z(c){} 12 }; 13 struct cube 14 { 15 point a, b; 16 }c[maxn]; 17 struct edge 18 { 19 int x1, x2; 20 int y; 21 int flag; 22 edge(int a = 0, int b = 0, int c = 0, int d = 0) : x1(a), x2(b), y(c), flag(d){} 23 bool operator< (const edge& b)const 24 { 25 return y < b.y; 26 } 27 }e[maxn]; 28 29 struct node 30 { 31 int l, r; 32 int s; 33 int len1, len2, len3; 34 }t[maxn << 2]; 35 36 void pushup(int tar) 37 { 38 if (t[tar].s) 39 t[tar].len1 = x[t[tar].r + 1] - x[t[tar].l]; 40 else if (t[tar].l == t[tar].r) 41 t[tar].len1 = 0; 42 else t[tar].len1 = t[tar << 1].len1 + t[tar << 1 | 1].len1; 43 44 if (t[tar].s >= 2) 45 t[tar].len2 = x[t[tar].r + 1] - x[t[tar].l]; 46 else if (t[tar].l == t[tar].r) 47 t[tar].len2 = 0; 48 else if (t[tar].s == 1) 49 t[tar].len2 = t[tar << 1].len1 + t[tar << 1 | 1].len1; 50 else t[tar].len2 = t[tar << 1].len2 + t[tar << 1 | 1].len2; 51 52 if (t[tar].s >= 3) 53 t[tar].len3 = x[t[tar].r + 1] - x[t[tar].l]; 54 else if (t[tar].l == t[tar].r) 55 t[tar].len3 = 0; 56 else if (t[tar].s == 2) 57 t[tar].len3 = t[tar << 1].len1 + t[tar << 1 | 1].len1; 58 else if (t[tar].s == 1) 59 t[tar].len3 = t[tar << 1].len2 + t[tar << 1 | 1].len2; 60 else t[tar].len3 = t[tar << 1].len3 + t[tar << 1 | 1].len3; 61 } 62 63 void build(int l, int r, int tar) 64 { 65 t[tar].l = l, t[tar].r = r, t[tar].s = t[tar].len1 = t[tar].len2 = t[tar].len3 = 0; 66 if (l == r) return; 67 int mid = (l + r) >> 1; 68 build(l, mid, tar << 1), build(mid + 1, r, tar << 1 | 1); 69 } 70 71 void update(int l, int r, int v, int tar) 72 { 73 if (t[tar].l == l && t[tar].r == r) 74 { 75 t[tar].s += v; 76 pushup(tar); 77 return; 78 } 79 int mid = (t[tar].l + t[tar].r) >> 1; 80 if (r <= mid) update(l, r, v, tar << 1); 81 else if (l > mid) update(l, r, v, tar << 1 | 1); 82 else update(l, mid, v, tar << 1), update(mid + 1, r, v, tar << 1 | 1); 83 pushup(tar); 84 } 85 86 int main() 87 { 88 int T; cin >> T; 89 int cases = 0; 90 while (T--) 91 { 92 int n; cin >> n; 93 int numz = 0, numx = 0; 94 int nume = 0; 95 96 for (int i = 1; i <= n; i++) 97 { 98 scanf("%d%d%d%d%d%d", &c[i].a.x, &c[i].a.y, &c[i].a.z, &c[i].b.x, &c[i].b.y, &c[i].b.z); 99 z[++numz] = c[i].a.z, z[++numz] = c[i].b.z; 100 } 101 sort(z + 1, z + 1 + numz); 102 numz = unique(z + 1, z + 1 + numz) - z - 1; 103 ll res = 0; 104 for (int i = 1; i < numz; i++) 105 { 106 nume = numx = 0; 107 for (int j = 1; j <= n; j++) 108 if (c[j].a.z <= z[i] && c[j].b.z > z[i]) 109 { 110 e[++nume] = edge(c[j].a.x, c[j].b.x, c[j].a.y, 1); 111 e[++nume] = edge(c[j].a.x, c[j].b.x, c[j].b.y, -1); 112 x[++numx] = c[j].a.x, x[++numx] = c[j].b.x; 113 } 114 sort(x + 1, x + 1 + numx); 115 numx = unique(x + 1, x + 1 + numx) - x - 1; 116 build(1, numx - 1, 1); 117 sort(e + 1, e + 1 + nume); 118 ll res1 = 0; 119 for (int j = 1; j < nume; j++) 120 { 121 int x1, x2; 122 x1 = lower_bound(x + 1, x + 1 + numx, e[j].x1) - x; 123 x2 = lower_bound(x + 1, x + 1 + numx, e[j].x2) - x; 124 update(x1, x2 - 1, e[j].flag, 1); 125 res1 += (long long)t[1].len3 * (e[j + 1].y - e[j].y); 126 } 127 res += res1 * (z[i + 1] - z[i]); 128 } 129 printf("Case %d: %lld ", ++cases, res); 130 } 131 }