//#pragma GCC optimize("Ofast,unroll-loops")
//#pragma GCC target("avx2,tune=native")
#include <bits/stdc++.h>
using namespace std;
#define ff(i, a, b) for(auto i=(a); i<=(b); ++i)
#define ffr(i, b, a) for(auto i=(b); i>=(a); --i)
#define nl "\n"
#define pb emplace_back
#define sz(s) (int)s.size()
typedef long long ll;
typedef vector<int> vi;
int main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
int tt; if(!(cin>>tt)) return 0;
while(tt--){
int X,Y,Z; cin>>X>>Y>>Z;
vector<vector<vector<int>>> a(X, vector<vector<int>>(Y, vector<int>(Z,0)));
ff(x,0,X-1) ff(y,0,Y-1) ff(z,0,Z-1) cin>>a[x][y][z];
// collect positions that are 1 and map to index
vector<int> posList; posList.reserve(X*Y*Z);
vector<int> lin2idx(X*Y*Z, -1);
int U = 0;
ff(x,0,X-1) ff(y,0,Y-1) ff(z,0,Z-1){
if(a[x][y][z]==1){
int lin = (x*Y + y)*Z + z;
lin2idx[lin] = U++;
posList.pb(lin);
}
}
if(U==0){
cout<<0<<nl;
continue;
}
// build 3D prefix sum (1-based)
vector<vector<vector<int>>> pref(X+1, vector<vector<int>>(Y+1, vector<int>(Z+1,0)));
for(int x=1;x<=X;x++) for(int y=1;y<=Y;y++) for(int z=1;z<=Z;z++){
pref[x][y][z] = a[x-1][y-1][z-1]
+ pref[x-1][y][z] + pref[x][y-1][z] + pref[x][y][z-1]
- pref[x-1][y-1][z] - pref[x-1][y][z-1] - pref[x][y-1][z-1]
+ pref[x-1][y-1][z-1];
}
auto sum_box = [&](int x1,int x2,int y1,int y2,int z1,int z2)->int{
// inputs 1-based inclusive
int s = pref[x2][y2][z2]
- pref[x1-1][y2][z2] - pref[x2][y1-1][z2] - pref[x2][y2][z1-1]
+ pref[x1-1][y1-1][z2] + pref[x1-1][y2][z1-1] + pref[x2][y1-1][z1-1]
- pref[x1-1][y1-1][z1-1];
return s;
};
// enumerate all boxes that are fully 1
struct Box { int cost; vector<int> elems; };
vector<Box> boxes;
boxes.reserve(10000);
// enumerate all boxes: complexity ok since X*Y*Z <= 5000
for(int x1=1;x1<=X;x1++){
for(int x2=x1;x2<=X;x2++){
for(int y1=1;y1<=Y;y1++){
for(int y2=y1;y2<=Y;y2++){
for(int z1=1;z1<=Z;z1++){
for(int z2=z1;z2<=Z;z2++){
int vol = (x2-x1+1)*(y2-y1+1)*(z2-z1+1);
int s = sum_box(x1,x2,y1,y2,z1,z2);
if(s==vol && vol>0){
Box B;
B.cost = min({x2-x1+1, y2-y1+1, z2-z1+1});
B.elems.reserve(vol);
for(int x=x1-1;x<=x2-1;x++){
for(int y=y1-1;y<=y2-1;y++){
for(int z=z1-1;z<=z2-1;z++){
int lin = (x*Y + y)*Z + z;
int idx = lin2idx[lin];
if(idx!=-1) B.elems.pb(idx);
}
}
}
if(!B.elems.empty()) boxes.pb(move(B));
// small safeguard: avoid explosion
if((int)boxes.size() > 200000) break;
}
}
if((int)boxes.size() > 200000) break;
}
if((int)boxes.size() > 200000) break;
}
if((int)boxes.size() > 200000) break;
}
if((int)boxes.size() > 200000) break;
}
if((int)boxes.size() > 200000) break;
}
// If boxes exploded, fallback: use singletons (each 1×1×1)
if(boxes.empty()){
// fall back: each single 1-cell as a box (cost=1)
for(int i=0;i<U;i++){
Box B; B.cost = 1; B.elems = {i};
boxes.pb(move(B));
}
} else if((int)boxes.size() > 200000){
boxes.clear();
for(int i=0;i<U;i++){
Box B; B.cost = 1; B.elems = {i};
boxes.pb(move(B));
}
}
int M = boxes.size();
// covered flag
vector<char> covered(U, 0);
int remain = U;
int totalCost = 0;
// Precompute for speed: each box's elems vector and cost already
// Greedy loop: pick box with max (newly_covered / cost)
while(remain > 0){
double bestVal = -1.0;
int bestIdx = -1;
int bestNew = 0;
for(int i=0;i<M;i++){
int newly = 0;
for(int e : boxes[i].elems) if(!covered[e]) ++newly;
if(newly==0) continue;
double val = double(newly) / double(boxes[i].cost);
if(val > bestVal + 1e-12){
bestVal = val;
bestIdx = i;
bestNew = newly;
}
}
if(bestIdx==-1){
// something wrong -> cover remaining by singletons
totalCost += remain;
break;
}
totalCost += boxes[bestIdx].cost;
for(int e : boxes[bestIdx].elems){
if(!covered[e]) { covered[e]=1; --remain; }
}
}
cout<<totalCost<<nl;
}
return 0;
}