diff --git a/ex5/ex5.c b/ex5/ex5.c
index 07a61c08cc6aa8ac5c11b48456e5f0f3d9345b73..b06d07c010aa9950509555aa73f8e9c715dd1f60 100644
--- a/ex5/ex5.c
+++ b/ex5/ex5.c
@@ -16,30 +16,258 @@
 #include <stdlib.h>
 #include <string.h>
 
+// Matrix.h
+
+typedef struct Matrix {
+    int32_t m;
+    int32_t n;
+    int32_t **data;
+} Matrix;
+
+Matrix *matrix_init(int32_t m, int32_t n);
+void matrix_destroy(Matrix **matrix);
+int32_t matrix_get(Matrix *matrix, int32_t y, int32_t x);
+void matrix_set(Matrix *matrix, int32_t y, int32_t x, int32_t value);
+
+// Matrix.c
+
+Matrix *matrix_init(int32_t m, int32_t n) {
+    Matrix *matrix = (Matrix *)malloc(sizeof(Matrix));
+    matrix->m = m;
+    matrix->n = n;
+    matrix->data = (int32_t **)malloc(sizeof(int32_t *) * m);
+
+    for (int32_t i = 0; i < matrix->m; i += 1) {
+        matrix->data[i] = (int32_t *)calloc(n, sizeof(int32_t));
+    }
+
+    return matrix;
+}
+
+void matrix_destroy(Matrix **matrix) {
+    for (int32_t i = 0; i < (*matrix)->m; i += 1) {
+        free((*matrix)->data[i]);
+    }
+
+    free((*matrix)->data);
+    free(*matrix);
+    *matrix = NULL;
+}
+
+int32_t matrix_get(Matrix *matrix, int32_t y, int32_t x) {
+    return matrix->data[y][x];
+}
+
+void matrix_set(Matrix *matrix, int32_t y, int32_t x, int32_t value) {
+    matrix->data[y][x] = value;
+}
+
+void matrix_print(Matrix *matrix) {
+    for (int i = 0; i < matrix->m; i += 1) {
+        for (int j = 0; j < matrix->n; j += 1) {
+            printf("%2d ", matrix->data[i][j]);
+        }
+
+        printf("\n");
+    }
+}
+
+// Quadtree.h
+
+#define CHILDREN_COUNT 4
+
+typedef struct Node {
+    int data;
+    struct Node *children[CHILDREN_COUNT];
+} Node;
+
+int32_t _max(int32_t a, int32_t b);
+Node *node_init();
+Node *quadtree_init(int32_t depth);
+void quadtree_destroy(Node **root);
+int32_t quadtree_depth(Node *root);
+bool quadtree_is_leaf(Node *root);
+Node *quadtree_search(Node *root, int32_t depth, int32_t y, int32_t x);
+Node *matrix_to_quadtree(Matrix *matrix);
+Matrix *quadtree_to_matrix(Node *root);
+
+// Quadtree.c
+
+int32_t _max(int32_t a, int32_t b) {
+    return a > b ? a : b;
+}
+
+Node *node_init() {
+    Node *node = (Node *)malloc(sizeof(Node));
+    node->data = 0;
+
+    for (int32_t i = 0; i < CHILDREN_COUNT; i += 1) {
+        node->children[i] = NULL;
+    }
+
+    return node;
+}
+
+Node *quadtree_init(int32_t depth) {
+    Node *root = node_init();
+
+    if (depth == 0) {
+        return root;
+    }
+
+    for (int32_t i = 0; i < CHILDREN_COUNT; i += 1) {
+        root->children[i] = quadtree_init(depth - 1);
+    }
+
+    return root;
+}
+
+void quadtree_destroy(Node **root) {
+    if (!quadtree_is_leaf(*root)) {
+        for (int32_t i = 0; i < CHILDREN_COUNT; i += 1) {
+            quadtree_destroy(&(*root)->children[i]);
+        }
+    }
+
+    free(*root);
+    *root = NULL;
+}
+
+int32_t quadtree_depth(Node *root) {
+    if (root == NULL) {
+        return -1;
+    }
+
+    if (quadtree_is_leaf(root)) {
+        return 0;
+    }
+
+    int32_t biggest_depth = 0;
+
+    for (int32_t i = 0; i < CHILDREN_COUNT; i += 1) {
+        biggest_depth = _max(biggest_depth, quadtree_depth(root->children[i]));
+    }
+
+    return biggest_depth + 1;
+}
+
+bool quadtree_is_leaf(Node *root) {
+    return root->children[0] == NULL;
+}
+
+Node *quadtree_search(Node *root, int32_t depth, int32_t y, int32_t x) {
+    for (int32_t d = depth - 1; d >= 0; d -= 1) {
+        if (quadtree_is_leaf(root)) {
+            return root;
+        }
+
+        int32_t i = (y >> d) & 1;
+        int32_t j = (x >> d) & 1;
+        root = root->children[2 * i + j];
+    }
+
+    return root;
+}
+
+Node *matrix_to_quadtree(Matrix *matrix) {
+    int32_t depth = (int32_t)log2(matrix->m);
+    Node *root = quadtree_init(depth);
+
+    for (int32_t i = 0; i < matrix->m; i += 1) {
+        for (int32_t j = 0; j < matrix->n; j += 1) {
+            Node *node = quadtree_search(root, depth, i, j);
+            node->data = matrix_get(matrix, i, j);
+        }
+    }
+
+    return root;
+}
+
+Matrix *quadtree_to_matrix(Node *root) {
+    int32_t depth = quadtree_depth(root);
+    int32_t size = (int32_t)pow(2, depth);
+    Matrix *matrix = matrix_init(size, size);
+
+    for (int32_t i = 0; i < matrix->m; i++) {
+        for (int32_t j = 0; j < matrix->n; j++) {
+            Node *node = quadtree_search(root, depth, i, j);
+            int32_t value = node->data;
+            matrix_set(matrix, i, j, value);
+        }
+    }
+
+    return matrix;
+}
+
+// ---
+
+int quadtree_max(Node *root) {
+    if (quadtree_is_leaf(root)) {
+        return root->data;
+    }
+
+    int max_value = 0;
+    for (int i = 0; i < 4; i += 1) {
+        max_value = _max(max_value, quadtree_max(root->children[i]));
+    }
+
+    return max_value;
+}
+
+void transform(Node *root, int *indices, int indices_length) {
+    for (int i = 0; i < indices_length; i += 1) {
+        root = root->children[indices[i]];
+    }
+
+    int max_value = quadtree_max(root);
+    for (int32_t i = 0; i < CHILDREN_COUNT; i += 1) {
+        quadtree_destroy(&root->children[i]);
+    }
+    root->data = max_value;
+}
+
 int main() {
-    // int32_t values_length = 5;
-    // double values[values_length];
-
-    // for (int32_t i = 0; i < values_length; i += 1) {
-    //     double value;
-    //     scanf("%lf", &value);
-    //     values[i] = value;
-    // }
-
-    // int32_t values_length = 5;
-    // int32_t values[values_length];
-
-    // for (int32_t i = 0; i < values_length; i += 1) {
-    //     int32_t value;
-    //     scanf("%d", &value);
-    //     values[i] = value;
-    // }
-
-    // char a[100];
-    // int32_t b;
-    // scanf("%s %d", a, &b);
-    // printf("%s %d\n", a, b);
-
-    printf("ex1\n");
+    // !!!
+    int indices_length = 2;
+    int indices[] = {3, 1};
+
+    int n = 16;
+    int32_t input[16][16] = {
+        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+        {0, 3, 3, 3, 3, 0, 0, 7, 7, 7, 7, 0, 0, 11, 11, 11},
+        {0, 3, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 11, 0, 0},
+        {0, 3, 3, 3, 0, 0, 0, 7, 7, 7, 0, 0, 0, 11, 11, 11},
+        {0, 3, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 11, 0, 0},
+        {0, 3, 0, 0, 0, 0, 0, 7, 7, 7, 7, 0, 0, 11, 11, 11},
+        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+        {0, 3, 3, 3, 3, 0, 0, 7, 7, 7, 7, 0, 0, 11, 11, 11},
+        {0, 3, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 11, 0, 0},
+        {0, 3, 3, 3, 0, 0, 0, 7, 7, 7, 0, 0, 0, 11, 11, 11},
+        {0, 3, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 11, 0, 0},
+        {0, 3, 0, 0, 0, 0, 0, 7, 7, 7, 7, 0, 0, 11, 11, 11},
+        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+        {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+        {0, 3, 3, 3, 3, 0, 0, 7, 7, 7, 7, 0, 0, 11, 11, 11},
+    };
+
+    Matrix *matrix_input = matrix_init(n, n);
+
+    for (int i = 0; i < n; i += 1) {
+        for (int j = 0; j < n; j += 1) {
+            matrix_set(matrix_input, i, j, input[i][j]);
+        }
+    }
+
+    Node *tree = matrix_to_quadtree(matrix_input);
+    transform(tree, indices, indices_length);
+    Matrix *matrix_output = quadtree_to_matrix(tree);
+    quadtree_destroy(&tree);
+
+    // matrix_print(matrix_input);
+    matrix_print(matrix_output);
+
+    matrix_destroy(&matrix_input);
+    matrix_destroy(&matrix_output);
     return EXIT_SUCCESS;
 }