/*三体攻击
【题目描述】
三体人将对地球发起攻击。为了抵御攻击,地球人派出了 A × B × C 艘战舰,在太空中排成一个 A 层 B 行 C 列的立方体。其中,第 i 层第 j 行第 k 列的战舰(记为战舰 (i, j, k))的生命值为 d(i, j, k)。
三体人将会对地球发起 m 轮“立方体攻击”,每次攻击会对一个小立方体中的所有战舰都造成相同的伤害。具体地,第 t 轮攻击用 7 个参数 lat, rat, lbt, rbt, lct, rct, ht 描述;
所有满足 i ∈ [lat, rat],j ∈ [lbt, rbt],k ∈ [lct, rct] 的战舰 (i, j, k) 会受到 ht 的伤害。如果一个战舰累计受到的总伤害超过其防御力,那么这个战舰会爆炸。
地球指挥官希望你能告诉他,第一艘爆炸的战舰是在哪一轮攻击后爆炸的。
【输入格式】
从标准输入读入数据。
第一行包括 4 个正整数 A, B, C, m;
第二行包含 A × B × C 个整数,其中第 ((i - 1)×B + (j - 1)) × C + (k - 1)+1 个数为 d(i, j, k);
第 3 到第 m + 2 行中,第 (t - 2) 行包含 7 个正整数 lat, rat, lbt, rbt, lct, rct, ht。
【输出格式】
输出到标准输出。
输出第一个爆炸的战舰是在哪一轮攻击后爆炸的。保证一定存在这样的战舰。
【样例输入】
2 2 2 3
1 1 1 1 1 1 1 1
1 2 1 2 1 1 1
1 1 1 2 1 2 1
1 1 1 1 1 1 2
【样例输出】
2
【样例解释】
在第 2 轮攻击后,战舰 (1,1,1) 总共受到了 2 点伤害,超出其防御力导致爆炸。
【数据约定】
对于 10% 的数据,B = C = 1;
对于 20% 的数据,C = 1;
对于 40% 的数据,A × B × C, m ≤ 10, 000;
对于 70% 的数据,A, B, C ≤ 200;
对于所有数据,A × B × C ≤ 10^6, m ≤ 10^6, 0 ≤ d(i, j, k), ht ≤ 10^9。
资源约定:
峰值内存消耗(含虚拟机) < 256M
CPU消耗 < 2000ms
请严格按要求输出,不要画蛇添足地打印类似:“请您输入...” 的多余内容。
注意:
main函数需要返回0;
只使用ANSI C/ANSI C++ 标准;
不要调用依赖于编译环境或操作系统的特殊函数。
所有依赖的函数必须明确地在源文件中 #include <xxx>
不能通过工程设置而省略常用头文件。
提交程序时,注意选择所期望的语言类型和编译器类型。
*/
/* Time Limit Exceeded
#include<bits/stdc++.h>
using namespace std;
int A, B, C, m, a, b, c;
int getInt() {
char ch = getchar();
int x = 0, f = 1;
while (ch < '0' || ch > '9') {
if (ch == '-') f = -1;
ch = getchar();
}
while ('0' <= ch && ch <= '9') {
x = x * 10 + ch - '0';
ch = getchar();
}
return x * f;
}
inline int getIndex(int x, int y, int z) {
return ((x - 1) * b + (y - 1)) * c + z;
}
int main() {
ios_base::sync_with_stdio(false);
cin.tie(NULL);
cout.tie(NULL);
A = getInt();
B = getInt();
C = getInt();
m = getInt();
a = A + 1;
b = B + 1;
c = C + 1;
int *data = new int[a * b * c];
int (*atk)[7] = new int[m + 1][7];
for (int i = 1; i <= A; ++i) {
for (int j = 1; j <= B; ++j) {
for (int k = 1; k <= C; ++k) {
data[getIndex(i, j, k)] = getInt();
}
}
}
for (int i = 1; i <= m; ++i) {
for (int j = 0; j < 7; ++j) {
atk[i][j] = getInt();
}
//执行攻击
for (int x = atk[i][0]; x <= atk[i][1]; ++x) {//A的范围
for (int y = atk[i][2]; y <= atk[i][3]; ++y) {
for (int z = atk[i][4]; z <= atk[i][5]; ++z) {
data[getIndex(x, y, z)] -= atk[i][6];
if (data[getIndex(x, y, z)] < 0) {
cout << i << '\n';
delete[]data;
delete[]atk;
return 0;
}
}
}
}
}
delete[]data;
delete[]atk;
return 0;
}
*/
#include<bits/stdc++.h>
using namespace std;
#define loop(i, x, y) for(register int i=(x);i<=(y);i++)
#define loop_d(i, x, y) for(register int i=(x);i>=(y);i--)
// ijk均从1开始计数
#define getX(i, j, k) (((i)-1)*b+((j)-1))*c+(k)
int A, B, C, m, a, b, c;
void add(long long cc[], int i, int j, int k, int h) {
if (i < a && j < b && k < c)
cc[getX(i, j, k)] += h;
}
// O(8)
void op(long long cc[], int *atk, int x) {
int la = atk[0], ra = atk[1], lb = atk[2], rb = atk[3], lc = atk[4], rc = atk[5], h = x * atk[6];
add(cc, la, lb, lc, h);
add(cc, la, rb + 1, lc, -h);
add(cc, la, lb, rc + 1, -h);
add(cc, la, rb + 1, rc + 1, h);
add(cc, ra + 1, lb, lc, -h);
add(cc, ra + 1, rb + 1, lc, h);
add(cc, ra + 1, lb, rc + 1, h);
add(cc, ra + 1, rb + 1, rc + 1, -h);
}
//地推得到:差分数组的前缀和 O(ABC)
bool check(long long sum[], const long long d[]) {
loop(i, 2, A)loop(j, 1, B)loop(k, 1, C)sum[getX(i, j, k)] += sum[getX(i - 1, j, k)];
loop(i, 1, A)loop(j, 2, B)loop(k, 1, C)sum[getX(i, j, k)] += sum[getX(i, j - 1, k)];
loop(i, 1, A)loop(j, 1, B)loop(k, 2, C)sum[getX(i, j, k)] += sum[getX(i, j, k - 1)];
loop(i, 1, A)loop(j, 1, B)loop(k, 1, C) if (sum[getX(i, j, k)] > d[getX(i, j, k)])
return true;
return false;
}
int main() {
ios_base::sync_with_stdio(false);
cin.tie(NULL);
cout.tie(NULL);
cin >> A >> B >> C >> m;
a = A + 1;
b = B + 1;
c = C + 1;
long long *cc = new long long[a * b * c];//差分数组
long long *d = new long long[a * b * c];//原始血量
long long *sum = new long long[a * b * c];//差分数组的前缀和
int (*atk)[7] = new int[m + 1][7];//攻击数据
//输入血量
loop(i, 1, A)loop(j, 1, B)loop(k, 1, C)cin >> d[getX(i, j, k)];//原始血量
//输入攻击数据
loop(i, 1, m)loop(j, 0, 6)cin >> atk[i][j];
int l = 1, r = m, lastMid = 0;
while (l < r) {
int mid = (l + r) >> 1;
if (lastMid < mid)//上一次攻击没有攻破,继续攻击
for (int i = lastMid + 1; i <= mid; ++i) {
op(cc, atk[i], 1);
}
if (lastMid > mid)//上一次攻破了,恢复血量
for (int i = mid + 1; i <= lastMid; ++i) {
op(cc, atk[i], -1);
}
memcpy(sum, cc, sizeof(long long) * a * b * c);//将差分数组拷贝给前缀和数组
if (check(sum, d))//求差分数组的前缀和,同时与原始血量作比较
r = mid;
else
l = mid + 1;
lastMid = mid;
}
cout << r << '\n';
delete[] cc;
delete[]d;
return 0;
}