diff --git a/01-tree_successor/cpp/Makefile b/01-tree_successor/cpp/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..30f0b25a40595cc4423ba7bd8ace6b324e74f677
--- /dev/null
+++ b/01-tree_successor/cpp/Makefile
@@ -0,0 +1,12 @@
+test: tree_successor_test
+	./$<
+
+CXXFLAGS=-std=c++23 -O2 -Wall -Wextra -g -Wno-sign-compare
+
+tree_successor_test: tree_successor.h tree_successor_test.cpp test_main.cpp
+	$(CXX) $(CXXFLAGS) $^ -o $@
+
+clean:
+	rm -f tree_successor_test
+
+.PHONY: clean test
diff --git a/01-tree_successor/cpp/test_main.cpp b/01-tree_successor/cpp/test_main.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..3f4aff0785f636b7fd0ea1a15aa69dafe06f290f
--- /dev/null
+++ b/01-tree_successor/cpp/test_main.cpp
@@ -0,0 +1,43 @@
+#include <cstdlib>
+#include <functional>
+#include <iostream>
+#include <string>
+#include <utility>
+#include <vector>
+
+using namespace std;
+
+extern vector<pair<string, function<void()>>> tests;
+
+void expect_failed(const string& message) {
+    cerr << "Test error: " << message << endl;
+    exit(1);
+}
+
+int main(int argc, char* argv[]) {
+    vector<string> required_tests;
+
+    if (argc > 1) {
+        required_tests.assign(argv + 1, argv + argc);
+    } else {
+        for (const auto& test : tests)
+            required_tests.push_back(test.first);
+    }
+
+    for (const auto& required_test : required_tests) {
+        bool found = false;
+        for (const auto& test : tests)
+            if (required_test == test.first) {
+                cerr << "Running test " << required_test << endl;
+                test.second();
+                found = true;
+                break;
+            }
+        if (!found) {
+            cerr << "Unknown test " << required_test << endl;
+            return 1;
+        }
+    }
+
+    return 0;
+}
diff --git a/01-tree_successor/cpp/tree_successor.h b/01-tree_successor/cpp/tree_successor.h
new file mode 100644
index 0000000000000000000000000000000000000000..106b5fc0365ea65887ab4fff71dc9d7dec568014
--- /dev/null
+++ b/01-tree_successor/cpp/tree_successor.h
@@ -0,0 +1,76 @@
+// A node of the tree
+class Node {
+  public:
+    int key;
+    Node* left;
+    Node* right;
+    Node* parent;
+
+    // Constructor
+    Node(int key, Node* parent=nullptr) {
+        this->key = key;
+        this->parent = parent;
+        this->left = nullptr;
+        this->right = nullptr;
+    }
+};
+
+// Binary tree
+class Tree {
+  public:
+    // Pointer to root of the tree; nullptr if the tree is empty.
+    Node* root = nullptr;
+
+    // Insert a key into the tree.
+    // If the key is already present, nothing happens.
+    // If the node is given, start searching a new position from that node.
+    Node* insert(int key, Node *node = nullptr) {
+        if (!root) {
+            root = new Node(key);
+            return root;
+        }
+
+        if (!node)
+            node = root;
+        while (node->key != key) {
+            if (key < node->key) {
+                if (!node->left)
+                    node->left = new Node(key, node);
+                node = node->left;
+            } else {
+                if (!node->right)
+                    node->right = new Node(key, node);
+                node = node->right;
+            }
+        }
+        return node;
+    }
+
+    // Return successor of the given node.
+    //
+    // The successor of a node is the node with the next higher key.
+    // Return nullptr if there is no such node.
+    // If the argument is nullptr, return the node with the smallest key.
+    Node* successor(Node* node) {
+        // TODO: Implement
+    }
+
+    // Destructor to free all allocated memory.
+    ~Tree() {
+        Node* node = root;
+        while (node) {
+            Node* next;
+            if (node->left) {
+                next = node->left;
+                node->left = nullptr;
+            } else if (node->right) {
+                next = node->right;
+                node->right = nullptr;
+            } else {
+                next = node->parent;
+                delete node;
+            }
+            node = next;
+        }
+    }
+};
diff --git a/01-tree_successor/cpp/tree_successor_test.cpp b/01-tree_successor/cpp/tree_successor_test.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..552762a5202ca4e15ca7d2dede05ec15447ef4df
--- /dev/null
+++ b/01-tree_successor/cpp/tree_successor_test.cpp
@@ -0,0 +1,105 @@
+#include <algorithm>
+#include <functional>
+#include <cstdint>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "tree_successor.h"
+
+using namespace std;
+
+// If the condition is not true, report an error and halt.
+#define EXPECT(condition, message) do { if (!(condition)) expect_failed(message); } while (0)
+void expect_failed(const string& message);
+
+void test(const vector<int>& sequence, Tree &tree) {
+    Node* node = tree.successor(nullptr);
+    for (const auto& element : sequence) {
+        EXPECT(node, "Expected successor " + to_string(element) + ", got nullptr");
+        EXPECT(node->key == element,
+               "Expected successor " + to_string(element) + ", got " + to_string(node->key));
+        node = tree.successor(node);
+    }
+    EXPECT(!node, "Expected no successor, got " + to_string(node->key));
+}
+
+vector<int> get_linear_sequence() {
+    vector<int> numbers;
+    for (int i = 0; i < 10000000; i++)
+        numbers.push_back((int)(7.13*i));
+    return numbers;
+}
+
+void test_path(bool right) {
+    vector<int> numbers = get_linear_sequence();
+    Tree tree;
+    Node *node = nullptr;
+    if (right)
+        for (int key : numbers)
+            node = tree.insert(key, node);
+    else
+        for (int index = numbers.size() - 1; index >= 0; --index)
+            node = tree.insert(numbers[index], node);
+
+    test(numbers, tree);
+}
+
+void test_two_paths() {
+    vector<int> numbers = get_linear_sequence();
+    Tree tree;
+    Node *node = nullptr;
+    for(size_t i = numbers.size()/2; i < numbers.size(); i++)
+        node = tree.insert(numbers[i], node);
+    node = nullptr;
+    for(int i = numbers.size()/2 - 1; i >= 0; i--)
+        node = tree.insert(numbers[i], node);
+
+    test(numbers, tree);
+}
+
+void test_sequence(vector<int> &&sequence) {
+    Tree tree;
+    for (const auto& element : sequence)
+        tree.insert(element);
+
+    sort(sequence.begin(), sequence.end());
+    test(sequence, tree);
+}
+
+void test_random() {
+    vector<int> sequence = {997};
+    for (int i = 2; i < 199999; i++)
+        sequence.push_back((sequence.back() * int64_t(997)) % 199999);
+    test_sequence(move(sequence));
+}
+
+void test_trivial() {
+    test_sequence({5});
+    test_sequence({7,9});
+    test_sequence({7,3});
+    test_sequence({5,3,7});
+}
+
+void test_comb() {
+    vector<int> numbers = get_linear_sequence();
+    Tree tree;
+    Node *node = nullptr;
+    for(size_t i = numbers.size()/2; i < numbers.size(); i++)
+        node = tree.insert(numbers[i], node);
+    node = nullptr;
+    for(int i = numbers.size()/2 - 1; i >= 0; i-=2) {
+        node = tree.insert(numbers[i-1], node);
+        tree.insert(numbers[i], node);
+    }
+    test(numbers, tree);
+}
+
+vector<pair<string, function<void()>>> tests = {
+    { "trivial", test_trivial },
+    { "right_path", []{ test_path(true); } },
+    { "left_path", []{ test_path(false); } },
+    { "random_tree", test_random },
+    { "two_paths", test_two_paths },
+    { "comb", test_comb }
+};
diff --git a/01-tree_successor/python/tree_successor.py b/01-tree_successor/python/tree_successor.py
new file mode 100644
index 0000000000000000000000000000000000000000..417ec9c04b3bd4d80bd2bc3a63a1000f0a91373a
--- /dev/null
+++ b/01-tree_successor/python/tree_successor.py
@@ -0,0 +1,51 @@
+#!/usr/bin/env python3
+
+class Node:
+    """Node in a binary tree `Tree`"""
+
+    def __init__(self, key, left=None, right=None, parent=None):
+        self.key = key
+        self.left = left
+        self.right = right
+        self.parent = parent
+
+class Tree:
+    """A simple binary search tree"""
+
+    def __init__(self, root=None):
+        self.root = root
+
+    def insert(self, key, node=None):
+        """Insert key into the tree.
+
+        If the key is already present, do nothing.
+        If the node is given, start searching a new position from that node.
+        """
+        if self.root is None:
+            self.root = Node(key)
+            return self.root
+
+        if not node:
+            node = self.root
+
+        while node.key != key:
+            if key < node.key:
+                if node.left is None:
+                    node.left = Node(key, parent=node)
+                node = node.left
+            else:
+                if node.right is None:
+                    node.right = Node(key, parent=node)
+                node = node.right
+
+        return node
+
+    def successor(self, node=None):
+        """Return successor of the given node.
+
+        The successor of a node is the node with the next greater key.
+        Return None if there is no such node.
+        If the argument is None, return the node with the smallest key.
+        """
+        # TODO: Implement
+        raise NotImplementedError
diff --git a/01-tree_successor/python/tree_successor_test.py b/01-tree_successor/python/tree_successor_test.py
new file mode 100644
index 0000000000000000000000000000000000000000..3415b8ff688ca141584343c5639bd1b905313614
--- /dev/null
+++ b/01-tree_successor/python/tree_successor_test.py
@@ -0,0 +1,80 @@
+#!/usr/bin/env python3
+import sys
+
+from tree_successor import Tree
+
+def test_tree(tree, sequence):
+    node = tree.successor(None)
+    for element in sequence:
+        assert node is not None, "Expected successor {}, got None".format(element)
+        assert node.key == element, "Expected successor {}, got {}".format(element, node.key)
+        node = tree.successor(node)
+    assert node is None, "Expected no successor, got {}".format(node.key)
+
+def test_sequence(sequence):
+    tree = Tree()
+    for i in sequence:
+        tree.insert(i)
+    sequence.sort()
+    test_tree(tree, sequence)
+
+def test_trivial_tree():
+    test_sequence([5])
+    test_sequence([7,9])
+    test_sequence([7,3])
+    test_sequence([5,3,7])
+
+def test_random_tree():
+    test_sequence([pow(997, i, 199999) for i in range(1, 199999)])
+
+def test_path(right):
+    sequence = [int(7.13*i) for i in range(1000000)]
+    tree = Tree()
+    node = None
+    sequence_insert = sequence if right else reversed(sequence)
+    for key in sequence_insert:
+        node = tree.insert(key, node)
+    test_tree(tree, sequence)
+
+def test_two_paths():
+    sequence_left = [int(7.13*i) for i in range(1000000)]
+    sequence_right = [int(7.13*i) for i in range(1000000, 2000000)]
+    tree = Tree()
+    node = None
+    for key in sequence_right:
+        node = tree.insert(key, node)
+    node = None
+    for key in reversed(sequence_left):
+        node = tree.insert(key, node)
+    test_tree(tree, sequence_left + sequence_right)
+
+def test_comb():
+    sequence = [int(7.13*i) for i in range(1000000)]
+    tree = Tree()
+    node = None
+    for i in range(len(sequence)//2, len(sequence)):
+        node = tree.insert(sequence[i], node)
+    node = None
+    for i in range(len(sequence)//2-1, 0, -2):
+        node = tree.insert(sequence[i-1], node)
+        tree.insert(sequence[i], node)
+    test_tree(tree, sequence)
+
+tests = [
+    ("trivial", test_trivial_tree),
+    ("random_tree", test_random_tree),
+    ("right_path", lambda: test_path(True)),
+    ("left_path", lambda: test_path(False)),
+    ("two_paths", test_two_paths),
+    ("comb", test_comb),
+]
+
+if __name__ == "__main__":
+    for required_test in sys.argv[1:] or [name for name, _ in tests]:
+        for name, test in tests:
+            if name == required_test:
+                print("Running test {}".format(name), file=sys.stderr)
+                test()
+                break
+        else:
+            raise ValueError("Unknown test {}".format(name))
diff --git a/01-tree_successor/task.md b/01-tree_successor/task.md
new file mode 100644
index 0000000000000000000000000000000000000000..ec268c46e235ad886e1f3171e7188b97f0acbe3c
--- /dev/null
+++ b/01-tree_successor/task.md
@@ -0,0 +1,17 @@
+# `tree_successor`
+
+Given an implementation of a simple binary search tree including parent
+pointers, implement a `successor` method. The methods is given a node
+and it should return another node of the tree with the next higher key
+(i.e., the smallest of keys which are greater than the given one).
+
+- If there is no such node, it should return a null pointer.
+- The given node can also be a null pointer, in which case the method should
+  return the smallest node in the tree.
+
+You can expect that `successor` method is never called on an empty tree.
+
+You should submit the file `tree_successor.*` (but not the
+`tree_successor_test.*`).
+
+Source code templates can be found in [the git repository](https://gitlab.kam.mff.cuni.cz/datovky/assignments/-/tree/master).