diff --git a/algorithms/geometry/convex_hull.cpp b/algorithms/geometry/convex_hull.cpp
index 961fd505a0951cddd8d4fbb0249d96a33068d069..387467042daf4230d814b610d4e1a5fc3068a34e 100644
--- a/algorithms/geometry/convex_hull.cpp
+++ b/algorithms/geometry/convex_hull.cpp
@@ -3,9 +3,8 @@
 /// Complexity (Time): O(n log n)
 /// Complexity (Space): O(n)
 
-typedef pair<double,double> dd;
-
 struct ConvexHull {
+  using dd = pair<double,double>;
 
   /// The three points are a counter-clockwise turn if cross > 0, clockwise if
   /// cross < 0, and collinear if cross = 0
diff --git a/algorithms/graph/centroid_decomposition.cpp b/algorithms/graph/centroid_decomposition.cpp
index b6509c6c2bdf755e6fe7ebc3c0b3ded7b0f606ec..d9a34c0559eecf8f8c6d613767cce141a4583a84 100644
--- a/algorithms/graph/centroid_decomposition.cpp
+++ b/algorithms/graph/centroid_decomposition.cpp
@@ -6,6 +6,17 @@
 // Must be a tree
 vector<int> graph[MAX];
 
+/// The Centroid Decomposition of a tree is a tree where:
+///     - Its root is the centroid of the original tree.
+///     - Its children are the centroid of each tree resulting from the removal 
+///       of the root from the original tree.
+///   The result is a tree with lg(n) height, where the path from a to b in 
+/// the original tree can be decomposed into the path from a to lca(a,b) and 
+/// from lca(a,b) to b, where lca(a,b) is the lowest common ancestor of a and b
+/// in the centroid decomposition.
+///   This is useful because each one of the n^2 paths of the original tree is 
+/// the concatenation of two paths in a set of O(n lg(n)) paths from a node to 
+/// all its ancestors in the centroid decomposition.
 struct CentroidDecomposition {
   vector<int> par, size, marked;
 
diff --git a/algorithms/math/euler_totient.cpp b/algorithms/math/euler_totient.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..f41cdff24475a365225253a313717e36f1f4d411
--- /dev/null
+++ b/algorithms/math/euler_totient.cpp
@@ -0,0 +1,25 @@
+/// Euler Totient (phi)
+///
+/// Complexity (time): O(sqrt(n))
+/// Complexity (space): O(1)
+
+struct EulerTotient {
+
+  /// Returns phi(n) (i.e. the number of relative primes less than n)
+  /// @param n input number
+  int run(int n) {
+    int result = n;
+
+    for (int i = 2; i*i <= n; i++) {
+      if (n % i == 0) {
+        while (n % i == 0) n /= i;
+        result -= result / i;
+      }
+    }
+
+    if (n > 1)
+      result -= result / n;
+
+    return result;
+  }
+};
diff --git a/problems/exponial.cpp b/problems/exponial.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..1564e0fc538f86bf1260fca4963b6676fe1a271d
--- /dev/null
+++ b/problems/exponial.cpp
@@ -0,0 +1,78 @@
+#include <bits/stdc++.h>
+
+#define EPS 1e-6
+#define MOD 1000000007
+#define inf 0x3f3f3f3f
+#define llinf 0x3f3f3f3f3f3f3f3f
+
+#define fi first
+#define se second
+#define pb push_back
+#define ende '\n'
+
+#define all(x) (x).begin(), (x).end()
+#define rall(x) (x).rbegin(), (x).rend()
+#define mset(x, y) memset(&x, (y), sizeof(x))
+
+using namespace std; 
+
+using ll = long long;
+using ii = pair<int,int>;
+
+ll phi(ll n) {
+  ll result = n;
+
+  for (ll i = 2; i*i <= n; i++) {
+    if (n % i == 0) {
+      while (n % i == 0) n /= i;
+      result -= result / i;
+    }
+  }
+
+  if (n > 1)
+    result -= result / n;
+
+  return result;
+}
+
+ll fast_pow(ll x, ll n, ll m) {
+  ll ans = 1;
+
+  while (n) {
+    if (n & 1)
+      ans = (ans * x) % m;
+
+    n >>= 1;
+    x = (x * x) % m;
+  }
+
+  return ans % m;
+}
+
+ll solve(ll n, ll m) {
+  if (m == 1) 
+    return 0;
+
+  if (n <= 5) {
+    if (n == 4) return 262144 % m;
+    else if (n == 3) return 9 % m;
+    else if (n == 2) return 2 % m;
+    else if (n == 1) return 1 % m;
+    else return fast_pow(5, 262144, m);
+  }
+
+  // n^e % m == n^(phi(m) + e % phi(m)) mod m
+  ll p = phi(m);
+  ll e = p + solve(n - 1, p) % p;
+  return fast_pow(n, e, m); 
+}
+
+int main() {
+  ios::sync_with_stdio(0);
+  cin.tie(0);
+
+  ll n, m; cin >> n >> m;
+  cout << solve(n, m) << ende;
+
+  return 0;
+}