Cube Summation
Difficulty: Hard

[Chinese Version](https://hr-testcases.s3.amazonaws.com/1058/1058-chinese.md)<br/>
[Russian Version](https://hr-testcases.s3.amazonaws.com/1058/1058_rus.md)<br/>

Define a 3-D Matrix in which each block contains 0 initially. The first block is defined by the coordinates (1,1,1) and the last block is defined by the coordinates (n,n,n). There are two types of queries.

    UPDATE x y z W

Update the value of block (x,y,z) to W.

    QUERY x1 y1 z1 x2 y2 z2

Calculate the sum of the values of blocks whose x coordinate is between x1 and x2 (inclusive), y coordinate between y1 and y2 (inclusive) and z coordinate between z1 and z2 (inclusive). 

**Function Description**  

Complete the *cubeSum* function in the editor below.  

*cubeSum* has the following parameters:
- *int n: the dimensions of the 3-d matrix
- *string operations[m]:* the operations to perform  

**Returns**   
- *int[]:* the results of each `QUERY` operation  

**Input Format**  
The first line contains an integer $T$, the number of test-cases. $T$ testcases follow.  

For each test case, the first line contains two space-separated integers, $n$ and $m$. 
	$n$ defines the $n\times n\times n$ matrix.  
$m$ defines the number of operations.  
The next $m$ lines will contain an operation either of these forms:  

     1. UPDATE x y z W
     2. QUERY  x1 y1 z1 x2 y2 z2 



**Constraints**    
$1 \le T \le 50$  
$1 \le n \le 100$  
$1 \le m \le 1000$  
$1 \le x1 \le x2 \le n$  
$1 \le y1 \le y2 \le n$  
$1 \le z1 \le z2 \le n$  
$1 \le x,y,z \le n$  
-10<sup>9</sup> \le W \le 10<sup>9</sup>  

**Sample Input**

    2
    4 5
    UPDATE 2 2 2 4
    QUERY 1 1 1 3 3 3
    UPDATE 1 1 1 23
    QUERY 2 2 2 4 4 4
    QUERY 1 1 1 3 3 3
    2 4
    UPDATE 2 2 2 1
    QUERY 1 1 1 1 1 1
    QUERY 1 1 1 2 2 2
    QUERY 2 2 2 2 2 2

**Sample Output**

    4
    4
    27
    0
    1
    1

**Explanation**  
In the first test case, there is a cube of 4 * 4 * 4 and there are 5 queries.  Initially all the cells (1,1,1) to (4,4,4) are 0.  
`UPDATE 2 2 2 4` makes the cell (2,2,2) = 4  
`QUERY 1 1 1 3 3 3`. As (2,2,2) is updated to 4 and the rest are all 0. The answer to this query is 4.  
`UPDATE 1 1 1 23`. updates the cell (1,1,1) to 23. 
`QUERY 2 2 2 4 4 4`. Only the cell (1,1,1) and (2,2,2) are non-zero and (1,1,1) is not between (2,2,2) and (4,4,4). So, the answer is 4.   
`QUERY 1 1 1 3 3 3`. 2 cells are non-zero and their sum is 23+4 = 27. 


Input Format:

Output Format:

Sample Input:

Sample Output:

Python 3 starter code:
#
# Complete the 'cubeSum' function below.
#
# The function is expected to return an INTEGER_ARRAY.
# The function accepts following parameters:
#  1. INTEGER n
#  2. STRING_ARRAY operations
#

def cubeSum(n, operations):
    # Write your code here



Editorial: Cube Summation : 101 Hack January Editorial
<style id="MathJax_SVG_styles">.MathJax_SVG_Display {text-align: center; margin: 1em 0em; position: relative; display: block!important; text-indent: 0; max-width: none; max-height: none; min-width: 0; min-height: 0; width: 100%}
.MathJax_SVG .MJX-monospace {font-family: monospace}
.MathJax_SVG .MJX-sans-serif {font-family: sans-serif}
.MathJax_SVG {display: inline; font-style: normal; font-weight: normal; line-height: normal; font-size: 100%; font-size-adjust: none; text-indent: 0; text-align: left; text-transform: none; letter-spacing: normal; word-spacing: normal; word-wrap: normal; white-space: nowrap; float: none; direction: ltr; max-width: none; max-height: none; min-width: 0; min-height: 0; border: 0; padding: 0; margin: 0}
.MathJax_SVG * {transition: none; -webkit-transition: none; -moz-transition: none; -ms-transition: none; -o-transition: none}
.mjx-svg-href {fill: blue; stroke: blue}
</style><svg style="display: none;"><defs id="MathJax_SVG_glyphs"></defs></svg><p><a href="https://www.hackerrank.com/contests/101jan14/challenges/cube-summation">Cube Summation</a></p>

<p><strong>Difficulty Level</strong> : Medium <br>
<strong>Problem Setter</strong> : <a href="https://www.hackerrank.com/stranger9811">Ashok Kumar</a> <br>
<strong>Problem Testers</strong> : <a href="https://www.hackerrank.com/shashank21j">Shashank</a>, <a href="https://www.hackerrank.com/abhiranjan">Abhiranjan</a> <br>
<strong>Required Knowledge</strong> : <a href="https://en.wikipedia.org/wiki/Fenwick_tree">Binary Index Tree</a>  </p>

<p><strong>Approach</strong> <br>
This problem is based on <a href="https://en.wikipedia.org/wiki/Fenwick_tree">fenwick trees</a>. 
Consider this problem:</p>

<p><strong>A High level explanation of fenwick tree.</strong></p>

<p>Consider this problem:</p>

<p>Given an array(let say A) of size n initialized to zero. In this array only two operations can be performed </p>

<ol>
<li>update x</li>
<li>summation i j</li>
</ol>

<p>using fenwick tree both of these operation be done in O(logn) time.</p>

<p>First we have to construct a new array(let say B). B[i] stores summation of values of A[x] to A[i](here x is some index less than i). Now to get 
"summation x y" we have to calculate A[0]+....+A[j] and A[0]+....+A[i].</p>

<p>To get A[0]+....+A[j] we will make use of array B.</p>

<pre><code>sum = 0;
while(j&gt;0) {
      sum += B[j];
      j -= (j &amp; -j);        // consider updated j as x in above explanation. 
}
</code></pre>

<p>This while loops takes O(logn) time. Similarly we can perform update operation. </p>

<p>In original problem we have to find summation in 3-dimensions. So we can again use fenwick tree with three dimension. Now summation operation will look like this:</p>

<pre><code>    long long y1,x1,sum=0;
    while (z&gt;0) {
        x1=x;
        while(x1&gt;0) {
            y1=y;
            while(y1&gt;0) {
                sum += matrix[x1][y1][z];
                y1-= (y1 &amp; -y1);   
            }
            x1 -= (x1 &amp; -x1);
        }
        z -= (z &amp; -z);

    }
    return sum;
</code></pre>

<p><strong>Problem Setter's solution</strong></p>

<pre><code>#include&lt;iostream&gt;
#include&lt;cstdio&gt;
#include&lt;cstring&gt;

using namespace std;

long long matrix[101][101][101];


void update(long long n,long long x,long long y,long long z,long long  val) {
    long long y1,x1;

    while(z &lt;= n) {
        x1 = x;
        while(x1 &lt;= n) {
            y1 = y;
            while(y1 &lt;= n) {
                matrix[x1][y1][z] += val;
                y1 += (y1 &amp; -y1 );
            }
            x1 += (x1 &amp; -x1);
        }
        z += (z &amp; -z);
    }

}

long long calculate_sum(long long  x,long long y,long long z) {
    long long y1,x1,sum=0;
    while (z&gt;0) {
        x1=x;
        while(x1&gt;0) {
            y1=y;
            while(y1&gt;0) {
                sum += matrix[x1][y1][z];
                y1-= (y1 &amp; -y1);   
            }
            x1 -= (x1 &amp; -x1);
        }
        z -= (z &amp; -z);

    }
    return sum;
}

void process(long long n,long long m) {

    long long x,y,z,x0,y0,z0;
    long long value1,value2,val;
    char command[10];

    memset(matrix,0,sizeof(matrix));

    while(m--) {
        scanf("%s",command);

        if(!strcmp(command,"QUERY")) {
            scanf("%lld %lld %lld %lld %lld %lld",&amp;x0,&amp;y0,&amp;z0,&amp;x,&amp;y,&amp;z);

            value1 = calculate_sum(x,y,z)- calculate_sum(x0-1,y,z) 
                    - calculate_sum(x,y0-1,z) + calculate_sum(x0-1,y0-1,z);

            value2 = calculate_sum(x,y,z0-1) - calculate_sum(x0-1,y,z0-1)
                    - calculate_sum(x,y0-1,z0-1)  + calculate_sum(x0-1,y0-1,z0-1);

            printf("%lld\n",value1 - value2);
            //PrintMatrix(n);

        }

        if(!strcmp(command,"UPDATE")) {

            scanf("%lld %lld %lld %lld",&amp;x,&amp;y,&amp;z,&amp;val);
            x0 = x;
            y0 = y;
            z0 = z ;

            value1 = calculate_sum(x,y,z)- calculate_sum(x0-1,y,z) 
                    - calculate_sum(x,y0-1,z) + calculate_sum(x0-1,y0-1,z);
            value2 = calculate_sum(x,y,z0-1) - calculate_sum(x0-1,y,z0-1)
                    - calculate_sum(x,y0-1,z0-1)  + calculate_sum(x0-1,y0-1,z0-1);

            update(n,x,y,z,val -(value1 - value2 ));

        }

    }
}
int main() {
    long long cases; scanf("%lld",&amp;cases);
    while(cases--) {

        long long n,m; scanf("%lld %lld",&amp;n,&amp;m);
        process(n,m);
    }
    return 0;
}
</code></pre>

<p><strong>Tester's Solution</strong>  </p>

<pre><code>#include &lt;bits/stdc++.h&gt;
using namespace std;

const int sz = 111;

long long tree[sz][sz][sz];

void update(int x, int y, int z, long long val) {
    int xx = x;
    while(xx &lt; sz) {
        int yy = y;
        while(yy &lt; sz) {
            int zz = z;
            while(zz &lt; sz) {
                tree[xx][yy][zz] += val;    
                zz += zz &amp; (-zz);
            }
            yy += yy &amp; (-yy);
        }
        xx += xx&amp;(-xx);
    }
}

long long f(int x, int y, int z) {
    long long ret = 0;
    int xx = x;
    while(xx &gt; 0) {
        int yy = y;
        while(yy &gt; 0) {
            int zz = z;
            while(zz &gt; 0) {
                ret += tree[xx][yy][zz];
                zz -= zz &amp; (-zz);
            }
            yy -= yy &amp; (-yy);
        }
        xx -= xx &amp; (-xx);
    }
    return ret;
}

long long solve(int x1, int y1, int z1, int x2, int y2, int z2){
    long long j4 = f(x1-1, y1-1, z1-1);
    long long j1 = f(x2, y1-1, z1-1) - j4;
    long long j2 = f(x1-1, y2, z1-1) - j4;
    long long j3 = f(x1-1, y1-1, z2) - j4;

    return f(x2, y2, z2) - f(x2, y1-1, z2) - f(x1-1, y2, z2) - f(x2, y2, z1-1) + 2*j4 + j1 + j2 + j3;
}

int main()
{
    int test;
    scanf("%d", &amp;test);
    assert(test&gt;=1);
    assert(test&lt;=50);

    while(test--) {
        memset(tree, 0, sizeof(tree));
        int N, M;
        cin &gt;&gt; N &gt;&gt; M;
        assert(N&gt;=1);
        assert(N&lt;=100);
        assert(M&gt;=1);
        assert(M&lt;=1000);
        string st;
       int x1, y1, z1, x2, y2, z2;
       long long val;
        while(M--) {
            cin &gt;&gt; st;
            assert(st == "QUERY" || st == "UPDATE");
            if(st[0] == 'Q') {
                cin &gt;&gt; x1 &gt;&gt; y1 &gt;&gt; z1;
                cin &gt;&gt; x2 &gt;&gt; y2 &gt;&gt; z2;

                assert(1 &lt;= x1);
                assert(x1 &lt;= x2);
                assert(x2 &lt;= N);

                assert(1 &lt;= y1);
                assert(y1 &lt;= y2);
                assert(y2 &lt;= N);

                assert(1 &lt;= z1);
                assert(z1 &lt;= z2);
                assert(z2 &lt;= N);

                cout &lt;&lt; solve(x1, y1, z1, x2, y2, z2) &lt;&lt; "\n";
            }
            else if (st[0] == 'U') {
                cin &gt;&gt; x1 &gt;&gt; y1 &gt;&gt; z1 &gt;&gt; val;

                assert(1 &lt;= x1); assert(x1 &lt;= N);
                assert(1 &lt;= y1); assert(y1 &lt;= N);
                assert(1 &lt;= z1); assert(z1 &lt;= N);
                assert(-1e9 &lt;= val);
                assert(val &lt;= 1e9);

                long long existingVal = solve(x1, y1, z1, x1, y1, z1);
                update(x1, y1, z1, val-existingVal);
            }
        }
    }

    return 0;
}
</code></pre>

<p>Now Time Complexity of update and summation operation will be O((logn)^3). Since we have to reduce each x,y,z coordinate.</p>

Reference solution (C++):

	#include <bits/stdc++.h>
	using namespace std;

	const int sz = 111;

	long long tree[sz][sz][sz];

	void update(int x, int y, int z, long long val) {
		int xx = x;
		while(xx < sz) {
			int yy = y;
			while(yy < sz) {
				int zz = z;
				while(zz < sz) {
					tree[xx][yy][zz] += val;    
					zz += zz & (-zz);
				}
				yy += yy & (-yy);
			}
			xx += xx&(-xx);
		}
	}

	long long f(int x, int y, int z) {
		long long ret = 0;
		int xx = x;
		while(xx > 0) {
			int yy = y;
			while(yy > 0) {
				int zz = z;
				while(zz > 0) {
					ret += tree[xx][yy][zz];
					zz -= zz & (-zz);
				}
				yy -= yy & (-yy);
			}
			xx -= xx & (-xx);
		}
		return ret;
	}

	long long solve(int x1, int y1, int z1, int x2, int y2, int z2){
		long long j4 = f(x1-1, y1-1, z1-1);
		long long j1 = f(x2, y1-1, z1-1) - j4;
		long long j2 = f(x1-1, y2, z1-1) - j4;
		long long j3 = f(x1-1, y1-1, z2) - j4;

		return f(x2, y2, z2) - f(x2, y1-1, z2) - f(x1-1, y2, z2) - f(x2, y2, z1-1) + 2*j4 + j1 + j2 + j3;
	}

	int main()
	{
		int test;
		scanf("%d", &test);
		assert(test>=1);
		assert(test<=50);

		while(test--) {
			memset(tree, 0, sizeof(tree));
			int N, M;
			cin >> N >> M;
			assert(N>=1);
			assert(N<=100);
			assert(M>=1);
			assert(M<=1000);
			string st;
		   int x1, y1, z1, x2, y2, z2;
		   long long val;
			while(M--) {
				cin >> st;
				assert(st == "QUERY" || st == "UPDATE");
				if(st[0] == 'Q') {
					cin >> x1 >> y1 >> z1;
					cin >> x2 >> y2 >> z2;

					assert(1 <= x1);
					assert(x1 <= x2);
					assert(x2 <= N);

					assert(1 <= y1);
					assert(y1 <= y2);
					assert(y2 <= N);

					assert(1 <= z1);
					assert(z1 <= z2);
					assert(z2 <= N);

					cout << solve(x1, y1, z1, x2, y2, z2) << "\n";
				}
				else if (st[0] == 'U') {
					cin >> x1 >> y1 >> z1 >> val;

					assert(1 <= x1); assert(x1 <= N);
					assert(1 <= y1); assert(y1 <= N);
					assert(1 <= z1); assert(z1 <= N);
					assert(-1e9 <= val);
					assert(val <= 1e9);

					long long existingVal = solve(x1, y1, z1, x1, y1, z1);
					update(x1, y1, z1, val-existingVal);
				}
			}
		}

		return 0;
	}