Implementing Dynamic Resource Management with C++ STL Set

The problem requires managing a collection of distinct integer values (representing log lengths). We need to support two main operations: adding a unique value and retrieving/removing either an exact value or the one closest to it. Given the requirements for uniqueness and efficient searching, the std::set container in C++ is an ideal choice, as it maintains elements in a sorted order and provides logarithmic time complexity for insertions and lookups.

Core Logic and Data Structure

A std::set<int> ensures that all elements are unique and automatically sorted. This allows us to handle the "Already Exist" condition during insertion and use binary search-based iterators to find the closest neighbors during deletion.

std::set<int> storage;

Operation 1: Insertion

When adding a new value, we first check if it already exists in the set. If it does, we output a warning message. Otherwise, we insert it into the container.

if (op == 1) {
    if (storage.count(length)) {
        std::cout << "Already Exist" << std::endl;
    } else {
        storage.insert(length);
    }
}

Operation 2: Retrieval and Deletion

This operation is more complex as it involves finding the nearest value when an exact match is missing. We must handle three scenarios:

  1. Empty Collection: If the set is empty, we simply output "Empty".
  2. Exact Match: If the value exists, we print and remove it.
  3. Nearest Match: If the value is missing, we identify the two elements adjacent to where the value would be (the predecessor and successor) and determine which is closer.

To find the neighbors, we use lower_bound, wich returns an iterator to the first element not less than the target value.

if (op == 2) {
    if (storage.empty()) {
        std::cout << "Empty" << std::endl;
        continue;
    }

    auto it = storage.lower_bound(length);
    
    // Exact match found
    if (it != storage.end() && *it == length) {
        std::cout << *it << std::endl;
        storage.erase(it);
    } else {
        // Find neighbors
        if (it == storage.begin()) {
            // No smaller element exists
            std::cout << *it << std::endl;
            storage.erase(it);
        } else if (it == storage.end()) {
            // No larger element exists
            it--;
            std::cout << *it << std::endl;
            storage.erase(it);
        } else {
            // Compare distance to predecessor and successor
            auto next_it = it;
            auto prev_it = --it;
            
            int dist_prev = length - *prev_it;
            int dist_next = *next_it - length;
            
            if (dist_prev <= dist_next) {
                std::cout << *prev_it << std::endl;
                storage.erase(prev_it);
            } else {
                std::cout << *next_it << std::endl;
                storage.erase(next_it);
            }
        }
    }
}

Implementation Details

The following complete implementation utilizes the logic above to process multiple commands efficiently. Note the use of std::set::lower_bound instead of std::lower_bound to ensure $O(\log N)$ performance.

#include <iostream>
#include <set>
#include <cmath>

int main() {
    int query_count;
    if (!(std::cin >> query_count)) return 0;

    std::set<int> logs;

    while (query_count--) {
        int command, val;
        std::cin >> command >> val;

        if (command == 1) {
            if (logs.find(val) != logs.end()) {
                std::cout << "Already Exist" << std::endl;
            } else {
                logs.insert(val);
            }
        } else {
            if (logs.empty()) {
                std::cout << "Empty" << std::endl;
                continue;
            }

            auto it_upper = logs.lower_bound(val);
            
            if (it_upper != logs.end() && *it_upper == val) {
                std::cout << *it_upper << std::endl;
                logs.erase(it_upper);
            } else {
                if (it_upper == logs.begin()) {
                    std::cout << *it_upper << std::endl;
                    logs.erase(it_upper);
                } else if (it_upper == logs.end()) {
                    auto it_prev = prev(it_upper);
                    std::cout << *it_prev << std::endl;
                    logs.erase(it_prev);
                } else {
                    auto it_prev = prev(it_upper);
                    if (val - *it_prev <= *it_upper - val) {
                        std::cout << *it_prev << std::endl;
                        logs.erase(it_prev);
                    } else {
                        std::cout << *it_upper << std::endl;
                        logs.erase(it_upper);
                    }
                }
            }
        }
    }
    return 0;
}

Tags: C++ STL Set Binary Search Data Structures

Posted on Sun, 05 Jul 2026 17:21:57 +0000 by bloom