题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3642
题目大意:给你n个立方体,求相交区域大于等于三次的体积和。
题目思路:同样的利用二维扫描线去维护xOy平面的矩形的面积。 然后对于每个不同的z找到符合要求的长方体
1 #include <cstdio>
2 #include <cstring>
3 #include <algorithm>
4 #include <vector>
5 #include <map>
6 using namespace std;
7 const int N = 2005;
8 struct Line {
9 int lx, h1, h2;
10 int flag;
11 Line(int a, int b, int c, int d):lx(a), h1(b), h2(c), flag(d) {}
12 bool operator < (const Line &a) const { return lx < a.lx; }
13 };
14 int n, flag[N << 2], cube[N][6];
15 int tree[4][N << 2];
16 vector<int> a, b;
17 vector<Line> line;
18 map<int, int> mp;
19
20 void pushup(int k, int left, int right) {
21 if (flag[k] > 2) {
22 tree[3][k] = tree[0][k];
23 tree[2][k] = tree[1][k] = 0;
24 }
25 else if (flag[k] == 2) {
26 if (left + 1 == right) {
27 tree[2][k] = tree[0][k];
28 tree[1][k] = tree[3][k] = 0;
29 }
30 else {
31 tree[3][k] = tree[3][k * 2] + tree[3][k * 2 + 1] + tree[2][k * 2] + tree[2][k * 2 + 1] + tree[1][k * 2] + tree[1][k * 2 + 1];
32 tree[2][k] = tree[0][k] - tree[3][k];
33 tree[1][k] = 0;
34 }
35 }
36 else if (flag[k] == 1) {
37 if (left + 1 == right) {
38 tree[1][k] = tree[0][k];
39 tree[2][k] = tree[3][k] = 0;
40 }
41 else {
42 tree[3][k] = tree[3][k * 2] + tree[3][k * 2 + 1] + tree[2][k * 2] + tree[2][k * 2 + 1];
43 tree[2][k] = tree[1][k * 2] + tree[1][k * 2 + 1];
44 tree[1][k] = tree[0][k] - tree[3][k] - tree[2][k];
45 }
46 }
47 else {
48 if (left + 1 == right)
49 tree[3][k] = tree[2][k] = tree[1][k] = 0;
50 else {
51 tree[3][k] = tree[3][k * 2] + tree[3][k * 2 + 1];
52 tree[2][k] = tree[2][k * 2] + tree[2][k * 2 + 1];
53 tree[1][k] = tree[1][k * 2] + tree[1][k * 2 + 1];
54 }
55 }
56 }
57
58 void build(int k, int left, int right) {
59 tree[0][k] = a[right] - a[left];
60 tree[1][k] = tree[2][k] = tree[3][k] = flag[k] = 0;
61 if (left + 1 != right) {
62 int mid = (left + right) / 2;
63 build(k * 2, left, mid);
64 build(k * 2 + 1, mid, right);
65 }
66 }
67
68 void modify(int k, int left, int right, int l, int r, int v) {
69 if (l <= left && right <= r) {
70 flag[k] += v;
71 pushup(k, left, right);
72 return;
73 }
74 int mid = (left + right) / 2;
75 if (l < mid)
76 modify(k * 2, left, mid, l, r, v);
77 if (r > mid)
78 modify(k * 2 + 1, mid, right, l, r, v);
79 pushup(k, left, right);
80 }
81
82 int main() {
83 int t, cas = 1;
84 scanf("%d", &t);
85 while (t--) {
86 a.clear(), b.clear(), mp.clear();
87 scanf("%d", &n);
88 // a 记录 y ,b 记录 z
89 for (int i = 0; i < n; i++) {
90 scanf("%d%d%d%d%d%d", &cube[i][0], &cube[i][1], &cube[i][2], &cube[i][3], &cube[i][4], &cube[i][5]);
91 a.push_back(cube[i][1]);
92 a.push_back(cube[i][4]);
93 b.push_back(cube[i][2]);
94 b.push_back(cube[i][5]);
95 }
96 if (n < 3) {
97 printf("Case %d: 0\n", cas++);
98 continue;
99 }
100 sort(a.begin(), a.end());
101 a.erase(unique(a.begin(), a.end()), a.end());
102 sort(b.begin(), b.end());
103 b.erase(unique(b.begin(), b.end()), b.end());
104 int sz = a.size(), sz2 = b.size();
105 for (int i = 0; i < sz; i++)
106 mp[a[i]] = i;
107 build(1, 0, sz - 1);
108 long long res = 0;
109 for (int i = 0; i < sz2 - 1; i++) { // 枚举z
110 line.clear();
111 for (int j = 0; j < n; j++) {
112 if (cube[j][2] <= b[i] && cube[j][5] >= b[i + 1]) { // 找到合法的长方体
113 line.push_back(Line(cube[j][0], cube[j][1], cube[j][4], 1));
114 line.push_back(Line(cube[j][3], cube[j][1], cube[j][4], -1));
115 }
116 }
117 sort(line.begin(), line.end());
118 int sz3 = line.size();
119 for (int j = 0; j < sz3; j++) {
120 if (j != 0)
121 res += (b[i + 1] - b[i]) * (line[j].lx - line[j - 1].lx) * (long long)tree[3][1];
122 modify(1, 0, sz - 1, mp[line[j].h1], mp[line[j].h2], line[j].flag); // 和二维的扫描线是一样的
123 }
124 }
125 printf("Case %d: %lld\n", cas++, res);
126 }
127 return 0;
128 }