#ifndef LAYOUT_INC_CPP
#define LAYOUT_INC_CPP
#include <cassert>
#include <cstdio>
#include <vector>
#include <algorithm>
struct Layout {
typedef std::vector<Layout> List;
int sx, sy, sz;
int x0, x1;
int y0, y1;
int z0, z1;
inline Layout(): sx(), sy(), sz(), x0(), x1(), y0(), y1(), z0(), z1() { }
explicit inline Layout(int sx, int sy = 1, int sz = 1):
sx(sx), sy(sy), sz(sz), x0(), x1(sx), y0(), y1(sy), z0(), z1(sz) { }
inline Layout& expandX (int e0, int e1) { return sx += e0+e1, x0 += e0, x1 += e0, *this; }
inline Layout& expandY (int e0, int e1) { return sy += e0+e1, y0 += e0, y1 += e0, *this; }
inline Layout& expandZ (int e0, int e1) { return sz += e0+e1, z0 += e0, z1 += e0, *this; }
inline Layout& expandXY (int e0, int e1) { return expandX (e0, e1).expandY(e0, e1); }
inline Layout& expandXYZ(int e0, int e1) { return expandXY(e0, e1).expandZ(e0, e1); }
inline Layout& expandX (int e) { return expandX (e, e); }
inline Layout& expandY (int e) { return expandY (e, e); }
inline Layout& expandZ (int e) { return expandX (e, e); }
inline Layout& expandXY (int e) { return expandXY (e, e); }
inline Layout& expandXYZ(int e) { return expandXYZ(e, e); }
inline Layout& padX (int p0, int p1) { return x0 += p0, x1 -= p0, *this; }
inline Layout& padY (int p0, int p1) { return y0 += p0, y1 -= p0, *this; }
inline Layout& padZ (int p0, int p1) { return z0 += p0, z1 -= p0, *this; }
inline Layout& padXY (int p0, int p1) { return padX (p0, p1).padY(p0, p1); }
inline Layout& padXYZ(int p0, int p1) { return padXY(p0, p1).padZ(p0, p1); }
inline Layout& padX (int p) { return padX (p, p); }
inline Layout& padY (int p) { return padY (p, p); }
inline Layout& padZ (int p) { return padX (p, p); }
inline Layout& padXY (int p) { return padXY (p, p); }
inline Layout& padXYZ(int p) { return padXYZ(p, p); }
inline int getW() const { return x1 - x0; }
inline int getH() const { return y1 - y0; }
inline int getD() const { return z1 - z0; }
inline int getCount() const { return sx*sy*sz; }
inline int getActiveCount() const { return getW()*getH()*getD(); }
inline operator bool() const {
return x0 >= 0 && x0 < x1 && x1 <= sx
&& y0 >= 0 && y0 < y1 && y1 <= sy
&& z0 >= 0 && z0 < z1 && z1 <= sz;
}
inline bool isSameSizeWith(const Layout &b) const
{ return sx == b.sx && sy == b.sy && sz == b.sz; }
inline bool isSameActiveSizeWith(const Layout &b) const
{ return getW() == b.getW() && getH() == b.getH() && getD() == b.getD(); }
inline bool isSubLayoutOf(const Layout &b) const
{ return isSameSizeWith(b) && b.x0 <= x0 && x0 < x1 && x1 <= b.x1; }
inline bool isParentLayoutOf(const Layout &b) const
{ return b.isSubLayoutOf(*this); }
void splitX(List &list, int count) const {
if (count <= 0) return list.clear();
list.resize(count);
int v = x0, s = x1 - v;
for(int i = 0; i < count; ++i) {
Layout &l = list[i] = *this;
l.x0 = v;
l.x1 = (v += s/count + (i < s%count));
}
}
void splitY(List &list, int count) const {
if (count <= 0) return list.clear();
list.resize(count);
int v = y0, s = y1 - v;
for(int i = 0; i < count; ++i) {
Layout &l = list[i] = *this;
l.y0 = v;
l.y1 = (v += s/count + (i < s%count));
}
}
void splitZ(List &list, int count) const {
if (count <= 0) return list.clear();
list.resize(count);
int v = z0, s = z1 - v;
for(int i = 0; i < count; ++i) {
Layout &l = list[i] = *this;
l.z0 = v;
l.z1 = (v += s/count + (i < s%count));
}
}
void split(List &list, int count) const {
int h = getH(), w = getW(), d = getD();
if (h >= w && h >= d) splitY(list, count); else
if (w >= d) splitX(list, count); else
splitZ(list, count);
}
void print(const char *prefix = nullptr) const {
if (prefix && *prefix) printf("%s: ", prefix);
printf("x: %d (%d-%d), y: %d (%d-%d), z: %d (%d-%d)\n", sx, x0, x1, sy, y0, y1, sz, z0, z1);
}
void printYXZ(const char *prefix = nullptr) const {
if (prefix && *prefix) printf("%s: ", prefix);
printf("y: %d (%d-%d), x: %d (%d-%d), z: %d (%d-%d)\n", sy, y0, y1, sx, x0, x1, sz, z0, z1);
}
};
#endif