diff --git a/contests/Cadernaveis/URI1464.cpp b/contests/Cadernaveis/URI1464.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..0b6b120bccb403e595ed270ffaae4e5723c04369
--- /dev/null
+++ b/contests/Cadernaveis/URI1464.cpp
@@ -0,0 +1,80 @@
+#include <bits/stdc++.h>
+
+#define MAX 0
+#define MOD 1000000007
+#define inf 0x3f3f3f3f
+
+#define fi first
+#define se second
+#define sz size()
+#define pb push_back
+#define all(x) (x).begin(), (x).end()
+#define rall(x) (x).rbegin(), (x).rend()
+
+using namespace std;
+
+typedef long long ll;
+typedef pair<int,int> ii;
+typedef pair<double,double> dd;
+
+
+double cross(dd a, dd b, dd c) {
+  return (b.fi - a.fi) * (c.se - a.se) - (b.se - a.se) * (c.fi - a.fi);
+}
+
+
+int convex_hull(vector<dd> &v) {
+  int k = 0;
+  vector<int> ans(v.sz * 2);
+
+  sort(v.begin(), v.end(), [](const dd &a, const dd &b) -> bool {
+    return (a.fi == b.fi) ? (a.se < b.se) : (a.fi < b.fi);
+  });
+
+  for (int i = 0; i < v.sz; ++i) {
+    while (k >= 2 && cross(v[ans[k - 2]], v[ans[k - 1]], v[i]) < 0) k--;
+    ans[k++] = i;
+  }
+
+  for (int i = v.sz - 2, t = k + 1; i >= 0; --i) {
+    while (k >= t && cross(v[ans[k - 2]], v[ans[k - 1]], v[i]) < 0) k--;
+    ans[k++] = i;
+  }
+
+  ans.resize(k);
+  sort(rall(ans));
+  ans.erase(unique(all(ans)), ans.end());
+
+  for (auto i : ans)
+    v.erase(v.begin() + i);
+
+  return k - 1;
+}
+
+
+int main() {
+  ios::sync_with_stdio(0);
+  cin.tie(0);
+
+  int n;
+  while (cin >> n && n) {
+    vector<dd> v;
+    double x, y;
+
+    for (int i = 0; i < n; ++i) {
+      cin >> x >> y;
+      v.pb(dd(x, y));
+    }
+
+    int ans = 0;
+    while (v.sz) {
+      convex_hull(v); 
+      ans++;
+    }
+
+    if (ans % 2) cout << "Take this onion to the lab!\n";
+    else cout << "Do not take this onion to the lab!\n";
+  }
+
+  return 0;
+}
diff --git a/geometry/convex_hull.cpp b/geometry/convex_hull.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..5a10e96b6ffbeaebf6202eb097addfbd6f692b58
--- /dev/null
+++ b/geometry/convex_hull.cpp
@@ -0,0 +1,49 @@
+/**
+ * Convex Hull 
+ *
+ * Complexity (Time): O(n log n)
+ * Complexity (Space): O(n)
+ */
+
+typedef pair<double,double> dd;
+
+// The three points are a counter-clockwise turn if cross > 0, clockwise if
+// cross < 0, and collinear if cross = 0
+double cross(dd a, dd b, dd c) {
+  return (b.fi - a.fi) * (c.se - a.se) - (b.se - a.se) * (c.fi - a.fi);
+}
+
+
+// Find, among v, the points that form a convex hull
+int convex_hull(const vector<dd> &v) {
+  int k = 0;
+  vector<int> ans(v.sz * 2);
+
+  // Sort points
+  sort(v.begin(), v.end(), [](const dd &a, const dd &b) -> bool {
+    return (a.fi == b.fi) ? (a.se < b.se) : (a.fi < b.fi);
+  });
+
+  // Uppermost part of convex hull
+  for (int i = 0; i < v.sz; ++i) {
+    while (k >= 2 && cross(v[ans[k - 2]], v[ans[k - 1]], v[i]) < 0) k--;
+    ans[k++] = i;
+  }
+
+  // Lowermost part of convex hull
+  for (int i = v.sz - 2, t = k + 1; i >= 0; --i) {
+    while (k >= t && cross(v[ans[k - 2]], v[ans[k - 1]], v[i]) < 0) k--;
+    ans[k++] = i;
+  }
+
+  // The ans vector contains the indices (relative to the sorted vector!) of 
+  // the points belonging to the convex hull
+  ans.resize(k);
+
+  // Remove duplicates
+  sort(all(ans));
+  ans.erase(unique(all(ans)), ans.end());
+
+  // Returns amount of point in the convex hull
+  return k - 1;
+}