diff --git a/01-tree_successor/cpp/tree_successor_more_tests.cpp b/01-tree_successor/cpp/tree_successor_more_tests.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..552762a5202ca4e15ca7d2dede05ec15447ef4df
--- /dev/null
+++ b/01-tree_successor/cpp/tree_successor_more_tests.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_more_tests.py b/01-tree_successor/python/tree_successor_more_tests.py
new file mode 100644
index 0000000000000000000000000000000000000000..3415b8ff688ca141584343c5639bd1b905313614
--- /dev/null
+++ b/01-tree_successor/python/tree_successor_more_tests.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
index ec268c46e235ad886e1f3171e7188b97f0acbe3c..1a95b5143580676d4b5bcc668b5b3c46c395629d 100644
--- a/01-tree_successor/task.md
+++ b/01-tree_successor/task.md
@@ -15,3 +15,8 @@ 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).
+
+Files tree_successor_more_tests.{cpp,py} contain additional tests
+for bugs discovered in students' solutions during this semester.
+They are not included on recodex, but your program should pass them 
+in few seconds.
diff --git a/02-splay_operation/cpp/splay_operation_more_tests.cpp b/02-splay_operation/cpp/splay_operation_more_tests.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..f70db3ff999d3cfbd6a76478b81dcabc0e467697
--- /dev/null
+++ b/02-splay_operation/cpp/splay_operation_more_tests.cpp
@@ -0,0 +1,209 @@
+#include <algorithm>
+#include <cassert>
+#include <fstream>
+#include <functional>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "splay_operation.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);
+
+// Flatten the tree: return a sorted list of all keys in the tree.
+vector<int> flatten(const Tree& tree) {
+    constexpr int L = 0, R = 1, F = 2;
+
+    Node* node = tree.root;
+    vector<int> flattened, stack = {L};
+    while (!stack.empty()) {
+        if (stack.back() == L) {
+            stack.back() = R;
+            if (node->left) {
+                node = node->left;
+                stack.push_back(L);
+            }
+        } else if (stack.back() == R) {
+            flattened.push_back(node->key);
+            stack.back() = F;
+            if (node->right) {
+                node = node->right;
+                stack.push_back(L);
+            }
+        } else {
+            node = node->parent;
+            stack.pop_back();
+        }
+    }
+    return flattened;
+}
+
+// Test for splay operation with required helpers
+class TestSplay {
+  public:
+    static Node* deserialize_node(const string& text, int& index) {
+        EXPECT(text[index++] == '(', "Internal error during example deserialization");
+        if (text[index] == ')') {
+            index++;
+            return nullptr;
+        } else {
+            int comma = text.find(',', index);
+            int key = stoi(text.substr(index, comma - index));
+            Node* left = deserialize_node(text, (index=comma + 1));
+            Node* right = deserialize_node(text, ++index);
+            EXPECT(text[index++] == ')', "Internal error during example deserialization");
+            return new Node(key, nullptr, left, right);
+        }
+    }
+
+    static Node* deserialize_root(const string& text) {
+        int index = 0;
+        Node* root = deserialize_node(text, index);
+        assert(index == text.size());
+        return root;
+    }
+
+    static string compare(Node* system, Node* gold) {
+        if (!system && gold) {
+            return "expected node with key " + to_string(gold->key) + ", found None";
+        } else if (system && !gold) {
+            return "expected None, found node with key " + to_string(system->key);
+        } else if (system && gold) {
+            if (system->key != gold->key)
+                return "expected node with key " + to_string(gold->key) + ", found " + to_string(system->key);
+            auto result = compare(system->left, gold->left);
+            if (!result.empty()) return result;
+            return compare(system->right, gold->right);
+        }
+        return string();
+    }
+
+    static void test() {
+        ifstream splay_tests_file("splay_tests.txt");
+        EXPECT(splay_tests_file.is_open(), "Cannot open splay_tests.txt file with the tests");
+
+        string original, splayed;
+        int target;
+        while (splay_tests_file >> original >> target >> splayed) {
+            Tree original_tree(deserialize_root(original));
+            Tree splayed_tree(deserialize_root(splayed));
+
+            Node* target_node = original_tree.root;
+            while (target_node && target_node->key != target)
+                if (target < target_node->key)
+                    target_node = target_node->left;
+                else
+                    target_node = target_node->right;
+            EXPECT(target_node, "Internal error during finding the target node in the tree to splay");
+
+            original_tree.splay(target_node);
+            auto error = compare(original_tree.root, splayed_tree.root);
+            EXPECT(error.empty(), "Error running splay on key " + to_string(target) + " of " + original + ": " + error);
+        }
+    }
+};
+
+const int elements = 5000000;
+
+void test_lookup() {
+    // Insert even numbers
+    Tree tree;
+    for (int i = 0; i < elements; i += 2)
+        tree.insert(i);
+
+    // Find non-existing
+    for (int i = 1; i < elements; i += 2)
+        for (int j = 0; j < 10; j++)
+            EXPECT(!tree.lookup(i), "Non-existing element was found");
+
+    // Find existing
+    for (int i = 0; i < elements; i += 2)
+        for (int j = 0; j < 10; j++)
+            EXPECT(tree.lookup(i), "Existing element was not found");
+}
+
+void test_insert() {
+    // Test validity first
+    {
+        Tree tree;
+        vector<int> sequence = {997};
+        for (int i = 2; i < 1999; i++)
+            sequence.push_back((sequence.back() * sequence.front()) % 1999);
+        for (const auto& i : sequence)
+            tree.insert(i);
+
+        vector<int> flattened = flatten(tree);
+        sort(sequence.begin(), sequence.end());
+        EXPECT(flattened == sequence, "Incorrect tree after a sequence of inserts");
+    }
+
+    // Test speed
+    {
+        Tree tree;
+        for (int i = 0; i < elements; i++)
+            for (int j = 0; j < 10; j++)
+                tree.insert(i);
+    }
+
+    {
+        Tree tree;
+        for (int i = elements; i >= 0; i--)
+            tree.insert(i);
+        for (int i = 0; i < elements; i++)
+            tree.insert(elements);
+    }
+}
+
+void test_remove() {
+    // Test validity first
+    {
+        Tree tree;
+        for (int i = 2; i < 1999 * 2; i++)
+            tree.insert(i);
+
+        vector<int> sequence = {2 * 997};
+        for (int i = 2; i < 1999; i++)
+            sequence.push_back(2 * ((sequence.back() * sequence.front() / 4) % 1999));
+        for (const auto& i : sequence)
+            tree.remove(i + 1);
+
+        vector<int> flattened = flatten(tree);
+        sort(sequence.begin(), sequence.end());
+        EXPECT(flattened == sequence, "Correct tree after a sequence of removes");
+    }
+
+    // Test speed
+    {
+        Tree tree;
+        for (int i = 0; i < elements; i++)
+            tree.insert(i);
+
+        // Non-existing elements
+        for (int i = 1; i < elements; i += 2)
+            for (int j = 0; j < 10; j++)
+                tree.remove(i);
+
+        // Existing elements
+        for (int i = 2; i < elements; i += 2)
+            for (int j = 0; j < 10; j++)
+                tree.remove(i);
+    }
+    {
+        Tree tree;
+        for (int i = 1; i < elements; i++)
+            tree.insert(i);
+        for (int i = 1; i < elements; i++)
+            tree.remove(0);
+    }
+}
+
+vector<pair<string, function<void()>>> tests = {
+    { "splay", TestSplay::test },
+    { "lookup", test_lookup },
+    { "insert", test_insert },
+    { "remove", test_remove },
+};
diff --git a/02-splay_operation/python/splay_operation_more_tests.py b/02-splay_operation/python/splay_operation_more_tests.py
new file mode 100644
index 0000000000000000000000000000000000000000..1ebb8aa7e07cd64ce2b1cf6bd74307591f2f2cec
--- /dev/null
+++ b/02-splay_operation/python/splay_operation_more_tests.py
@@ -0,0 +1,159 @@
+#!/usr/bin/env python3
+import itertools
+import math
+import sys
+
+from splay_operation import Tree, Node
+
+def flatten(tree):
+    """Flatten given tree in ascending order."""
+    L, R, F = 0, 1, 2
+
+    node, stack, flattened = tree.root, [L], []
+    while node is not None:
+        if stack[-1] == L:
+            stack[-1] = R
+            if node.left is not None:
+                node = node.left
+                stack.append(L)
+        elif stack[-1] == R:
+            flattened.append(node.key)
+            stack[-1] = F
+            if node.right is not None:
+                node = node.right
+                stack.append(L)
+        else:
+            node = node.parent
+            stack.pop()
+
+    return flattened
+
+def test_splay():
+    def deserialize_tree(string):
+        def deserialize_node(i):
+            assert string[i] == "("
+            i += 1
+            if string[i] == ")":
+                return i + 1, None
+            else:
+                comma = string.find(",", i)
+                comma2, left = deserialize_node(comma + 1)
+                rparen, right = deserialize_node(comma2 + 1)
+                assert string[rparen] == ")"
+                return rparen + 1, Node(int(string[i : comma]), left=left, right=right)
+
+        index, root = deserialize_node(0)
+        assert index == len(string)
+        return Tree(root)
+
+    def compare(system, gold):
+        if system is None and gold is not None:
+            return "expected node with key {}, found None".format(gold.key)
+        elif system is not None and gold is None:
+            return "expected None, found node with key {}".format(system.key)
+        elif system is not None and gold is not None:
+            if system.key != gold.key:
+                return "expected node with key {}, found {}".format(gold.key, system.key)
+            return compare(system.left, gold.left) or compare(system.right, gold.right)
+
+    with open("splay_tests.txt", "r") as splay_tests_file:
+        for line in splay_tests_file:
+            original_serialized, target_serialized, splayed_serialized = line.rstrip("\n").split()
+            original = deserialize_tree(original_serialized)
+            splayed = deserialize_tree(splayed_serialized)
+            target = int(target_serialized)
+
+            node = original.root
+            while node is not None and node.key != target:
+                if target < node.key: node = node.left
+                else: node = node.right
+            assert node is not None
+
+            original.splay(node)
+            error = compare(original.root, splayed.root)
+            assert not error, "Error running splay on key {} of {}: {}".format(node.key, original_serialized, error)
+
+def test_lookup():
+    tree = Tree()
+    for elem in range(0, 100000, 2):
+        tree.insert(elem)
+
+    # Find non-existing
+    for elem in range(1, 100000, 2):
+        for _ in range(10):
+            assert tree.lookup(elem) is None, "Non-existing element was found"
+
+    # Find existing
+    for elem in range(0, 100000, 2):
+        for _ in range(10):
+            assert tree.lookup(elem) is not None, "Existing element was not found"
+
+def test_insert():
+    # Test validity first
+    tree = Tree()
+    sequence = [pow(997, i, 1999) for i in range(1, 1999)]
+    for elem in sequence:
+        tree.insert(elem)
+    assert flatten(tree) == sorted(sequence), "Incorrect tree after a sequence of inserts"
+
+    # Test speed
+    elements = 200000
+    tree = Tree()
+    for elem in range(elements):
+        for _ in range(10):
+            tree.insert(elem)
+
+    tree = Tree()
+    for elem in reversed(range(elements)):
+        tree.insert(elem)
+    for elem in range(elements):
+        tree.insert(elements)
+
+def test_remove():
+    # Test validity first
+    tree = Tree()
+    for elem in range(2, 1999 * 2):
+        tree.insert(elem)
+
+    sequence = [2 * pow(997, i, 1999) for i in range(1, 1999)]
+    for elem in sequence:
+        tree.remove(elem + 1)
+    assert flatten(tree) == sorted(sequence), "Incorrect tree after a sequence of removes"
+
+    # Test speed
+    elements = 200000
+    tree = Tree()
+    for elem in range(0, elements, 2):
+        tree.insert(elem)
+
+    # Non-existing elements
+    for elem in range(1, elements, 2):
+        for _ in range(10):
+            tree.remove(elem)
+
+    # Existing elements
+    for elem in range(2, elements, 2):
+        tree.remove(elem)
+
+    tree = Tree()
+    for elem in range(1, elements):
+        tree.insert(elem)
+    for elem in range(elements):
+        tree.remove(0)
+
+tests = [
+    ("splay", test_splay),
+    ("lookup", test_lookup),
+    ("insert", test_insert),
+    ("remove", test_remove),
+]
+
+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/02-splay_operation/task.md b/02-splay_operation/task.md
index 18d722a6330ae91fd9978e489ad89bd25d5b86ee..665342ccca780408501f065208cdad4e3fadef3c 100644
--- a/02-splay_operation/task.md
+++ b/02-splay_operation/task.md
@@ -10,3 +10,8 @@ You should submit the `splay_operation.*` file (but not the
 `splay_operation_test.*`).
 
 Source code templates can be found in [the git repository](https://gitlab.kam.mff.cuni.cz/datovky/assignments/-/tree/master).
+
+Files splay_operation_more_tests.{cpp,py} contain additional tests
+for bugs discovered in students' solutions during this semester.
+They are not included on recodex, but your program should pass them 
+in few seconds.