In your first line,
using myarr = int(*)[mat_size][mat_size];
You're simply declaring a type: myarr is a custom type representing a pointer to a 2D array of int values. The using here is similar to typedef if you've worked with any older versions of C++.
Then,
int* data = new int[mat_size * mat_size];
declares a 1-dimensional pointer. In memory, this is a single series of values.
Next,
myarr arr = (myarr)data;
creates a new variable of type myarr - also a simple pointer - and points it to the address of the original array pointer. The difference with this pointer is that, when dereferenced the first time, it's an array type; thus its dereferencing syntax following the first dereference is different: as a 2-dimensional array, you use two pairs of brackets.
Notice, then, that this second array variable, in essence, still accesses a 1-dimensional array in the memory. In the first reference statement you have,
(*arr)[i][j]
To properly index into the array, C++ compiles the bracket syntax so that it'll automatically multiply the first index by the number of items in a single row. This was defined as part of your myarr, and was declared to be mat_size. Then, after this, it'll automatically add the second index.
(p.s. also don't get confused by the *arr part - the extra * is there because the myarr arr variable points to the data variable, not to the actual data array itself.)
Then, in your second statement,
data[i * mat_size + j]
you're using the original pointer, which has a nice bracket dereferencing syntax, but only dereferences as a 1-dimensional array. Because of this, you have to do the indexing yourself, manually multiplying the mat_size by the first index (i), and then manually adding the second (j).
Hope this helps!