Some checks failed
Build and Push Docker Images / build (src/LiquidCode.Tester.Gateway/Dockerfile, git.nullptr.top/liquidcode/liquidcode-tester-gateway-roman, gateway) (push) Successful in 1m12s
Build and Push Docker Images / build (src/LiquidCode.Tester.Worker/Dockerfile, git.nullptr.top/liquidcode/liquidcode-tester-worker-roman, worker) (push) Has been cancelled
281 lines
7.9 KiB
C++
281 lines
7.9 KiB
C++
#include<bits/stdc++.h>
|
|
|
|
#ifndef KRAKOZYABRA
|
|
#include "testlib.h"
|
|
#else
|
|
#include "testliblochal.h"
|
|
#endif // KRAKOZYABRA
|
|
|
|
using namespace std;
|
|
|
|
template <typename T>
|
|
class ordered_set {
|
|
private:
|
|
struct Node {
|
|
T data;
|
|
int weight; // Number of nodes in the subtree rooted at this node
|
|
std::unique_ptr<Node> left;
|
|
std::unique_ptr<Node> right;
|
|
|
|
Node(const T& data) : data(data), weight(1), left(nullptr), right(nullptr) {}
|
|
};
|
|
|
|
std::unique_ptr<Node> root;
|
|
|
|
// Helper function to update the weight of a node
|
|
void update_weight(Node* node) {
|
|
if (node) {
|
|
node->weight = 1;
|
|
if (node->left) node->weight += node->left->weight;
|
|
if (node->right) node->weight += node->right->weight;
|
|
}
|
|
}
|
|
|
|
// Helper function for insertion
|
|
Node* insert_recursive(Node* node, const T& data) {
|
|
if (!node) {
|
|
return new Node(data);
|
|
}
|
|
|
|
if (data < node->data) {
|
|
node->left.reset(insert_recursive(node->left.release(), data)); //Release ownership before recursive call
|
|
}
|
|
else {
|
|
node->right.reset(insert_recursive(node->right.release(), data)); //Release ownership before recursive call
|
|
}
|
|
update_weight(node);
|
|
return node;
|
|
}
|
|
|
|
// Helper function for deletion (find minimum in right subtree)
|
|
Node* find_min(Node* node) {
|
|
while (node->left) {
|
|
node = node->left.get(); // Access the raw pointer
|
|
}
|
|
return node;
|
|
}
|
|
|
|
// Helper function for deletion
|
|
Node* delete_recursive(Node* node, const T& data) {
|
|
if (!node) {
|
|
return nullptr; // Value not found
|
|
}
|
|
|
|
if (data < node->data) {
|
|
node->left.reset(delete_recursive(node->left.release(), data)); //Release ownership before recursive call
|
|
}
|
|
else if (data > node->data) {
|
|
node->right.reset(delete_recursive(node->right.release(), data)); //Release ownership before recursive call
|
|
}
|
|
else {
|
|
// Node to be deleted found
|
|
|
|
// Case 1: Node with no child or only one child
|
|
if (!node->left) {
|
|
Node* temp = node->right.release();
|
|
delete node;
|
|
return temp;
|
|
}
|
|
else if (!node->right) {
|
|
Node* temp = node->left.release();
|
|
delete node;
|
|
return temp;
|
|
}
|
|
|
|
// Case 2: Node with two children
|
|
Node* temp = find_min(node->right.get());
|
|
node->data = temp->data;
|
|
node->right.reset(delete_recursive(node->right.release(), temp->data));
|
|
}
|
|
|
|
update_weight(node);
|
|
return node;
|
|
}
|
|
|
|
//Helper for get_element_at_index (find the k-th smallest element).
|
|
T get_element_at_index_recursive(Node* node, int index) {
|
|
if (!node) {
|
|
throw std::out_of_range("Index out of range");
|
|
}
|
|
|
|
int left_subtree_size = (node->left) ? node->left->weight : 0;
|
|
|
|
if (index == left_subtree_size) {
|
|
return node->data;
|
|
}
|
|
else if (index < left_subtree_size) {
|
|
return get_element_at_index_recursive(node->left.get(), index);
|
|
}
|
|
else {
|
|
return get_element_at_index_recursive(node->right.get(), index - left_subtree_size - 1);
|
|
}
|
|
}
|
|
|
|
//Helper to perform inorder traversal
|
|
void inorder_traversal_recursive(Node* node, std::vector<T>& result) const {
|
|
if (node) {
|
|
inorder_traversal_recursive(node->left.get(), result);
|
|
result.push_back(node->data);
|
|
inorder_traversal_recursive(node->right.get(), result);
|
|
}
|
|
}
|
|
|
|
//Helper to find index of an element.
|
|
int get_index_of_element_recursive(Node* node, const T& target, int current_rank) const {
|
|
if (!node) {
|
|
return -1; // Element not found
|
|
}
|
|
|
|
int left_subtree_size = (node->left) ? node->left->weight : 0;
|
|
|
|
if (target == node->data) {
|
|
return current_rank + left_subtree_size;
|
|
}
|
|
else if (target < node->data) {
|
|
return get_index_of_element_recursive(node->left.get(), target, current_rank);
|
|
}
|
|
else {
|
|
return get_index_of_element_recursive(node->right.get(), target, current_rank + left_subtree_size + 1);
|
|
}
|
|
}
|
|
|
|
|
|
public:
|
|
ordered_set() : root(nullptr) {}
|
|
|
|
void insert(const T& data) {
|
|
if (!root) {
|
|
root = std::make_unique<Node>(data);
|
|
}
|
|
else {
|
|
root.reset(insert_recursive(root.release(), data)); //Release ownership before recursive call
|
|
}
|
|
}
|
|
|
|
void erase(const T& data) {
|
|
root.reset(delete_recursive(root.release(), data)); //Release ownership before recursive call
|
|
}
|
|
|
|
T get_element(int index) {
|
|
if (index < 0 || index >= size()) {
|
|
throw std::out_of_range("Index out of range");
|
|
}
|
|
return get_element_at_index_recursive(root.get(), index);
|
|
}
|
|
|
|
int size() const {
|
|
return (root) ? root->weight : 0;
|
|
}
|
|
|
|
bool empty() const {
|
|
return root == nullptr;
|
|
}
|
|
|
|
void clear() {
|
|
root.reset(); // Effectively deletes the entire tree
|
|
}
|
|
|
|
// Returns a vector of the elements in sorted order (inorder traversal)
|
|
std::vector<T> inorder_traversal() const {
|
|
std::vector<T> result;
|
|
inorder_traversal_recursive(root.get(), result);
|
|
return result;
|
|
}
|
|
|
|
// Added function to get the index of an element
|
|
int get_index(const T target) const {
|
|
return get_index_of_element_recursive(root.get(), target, 0);
|
|
}
|
|
};
|
|
|
|
int main(int argc, char* argv[]) {
|
|
#ifndef KRAKOZYABRA
|
|
registerGen(argc, argv, 1);
|
|
#endif // KRAKOZYABRA
|
|
|
|
|
|
int minN = opt<int>(2), maxN = opt<int>(3);
|
|
int minM = opt<int>(4), maxM = opt<int>(5);
|
|
int minA = opt<int>(6), maxA = opt<int>(7);
|
|
int n = rnd.next(minN, maxN);
|
|
int m = rnd.next(minM, maxM);
|
|
cout << n << ' ' << m << '\n';
|
|
ordered_set<int> st;
|
|
vector<int> a;
|
|
while (a.size() < n) {
|
|
int aa = rnd.next(minA, maxA);
|
|
if (st.get_index(aa) == -1) {
|
|
a.push_back(aa);
|
|
st.insert(aa);
|
|
}
|
|
}
|
|
|
|
auto getrndin = [&]() {
|
|
if (st.size() == 0)
|
|
return -1;
|
|
int sz = st.size();
|
|
int i = rnd.next(0, sz - 1);
|
|
return st.get_element(i);
|
|
};
|
|
auto getrndnew = [&]() {
|
|
int aa = rnd.next(minA, maxA);
|
|
while (st.get_index(aa) != -1)
|
|
aa = rnd.next(minA, maxA);
|
|
return aa;
|
|
};
|
|
|
|
for (int i = 0; i < n; i++)
|
|
cout << a[i] << " \n"[i == n - 1];
|
|
for (int i = 0; i < m; i++) {
|
|
int t = 0;
|
|
if (st.size() == 0)
|
|
t = 2;
|
|
else
|
|
t = rnd.next(1, 3);
|
|
if (t == 1) {
|
|
int x = getrndnew();
|
|
int y = getrndin();
|
|
st.insert(x);
|
|
cout << t << ' ' << x << ' ' << y << '\n';
|
|
}
|
|
if (t == 2) {
|
|
int x = getrndnew();
|
|
st.insert(x);
|
|
cout << t << ' ' << x << '\n';
|
|
}
|
|
if (t == 3) {
|
|
int x = getrndin();
|
|
st.erase(x);
|
|
cout << t << ' ' << x << '\n';
|
|
}
|
|
}
|
|
}
|
|
|
|
//#pragma once
|
|
//#include <bits/stdc++.h>
|
|
//#include <random>
|
|
//#include <optional>
|
|
//
|
|
//using namespace std;
|
|
//
|
|
//random_device rd;
|
|
//mt19937 gen(rd());
|
|
//
|
|
//template <typename T>
|
|
//T opt(T value) {
|
|
// FILE* stream;
|
|
// freopen_s(&stream, "params.txt", "r", stdin);
|
|
// T res;
|
|
// for (int i = 0; i < value; i++)
|
|
// cin >> res;
|
|
// return res;
|
|
//}
|
|
//
|
|
//class Random {
|
|
//public:
|
|
// long long next(long long a, long long b) {
|
|
// return a + gen() % (b - a + 1);
|
|
// };
|
|
//};
|
|
//
|
|
//Random rnd;
|