Get The Treasury (三维空间扫描线)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3642

 

题目大意:给你n个立方体,求相交区域大于等于三次的体积和。

 

题目思路:同样的利用二维扫描线去维护xOy平面的矩形的面积。 然后对于每个不同的z找到符合要求的长方体

 

  1 #include 
  2 #include 
  3 #include 
  4 #include 
  5 #include 
  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;
 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 }

 

你可能感兴趣的:(Get The Treasury (三维空间扫描线))