This documentation is automatically generated by online-judge-tools/verification-helper
View the Project on GitHub naskya/cp-library-cpp
#define PROBLEM "https://atcoder.jp/contests/abc185/tasks/abc185_f" #include <algorithm> #include <functional> #include <iostream> #include <iterator> #include "../../../include/data_structure/segment_tree.hpp" int main() { std::ios_base::sync_with_stdio(false); std::cin.tie(nullptr); int N, Q; std::cin >> N >> Q; lib::segment_tree<int, std::bit_xor<>> tree(N); { lib::no_range_query_in_this_scope query_lock(tree); for (int i = 0; i < N; ++i) { int buf; std::cin >> buf; tree.set(i, buf); } } while (Q--) { int t, x, y; std::cin >> t >> x >> y; --x; if (t == 1) tree.set(x, tree.get(x) ^ y); else std::cout << tree.prod(x, y) << '\n'; } }
#line 1 "test/data_structure/segment_tree/2.test.cpp" #define PROBLEM "https://atcoder.jp/contests/abc185/tasks/abc185_f" #include <algorithm> #include <functional> #include <iostream> #include <iterator> #line 1 "include/data_structure/segment_tree.hpp" //! @file segment_tree.hpp #ifndef CP_LIBRARY_SEGMENT_TREE_HPP #define CP_LIBRARY_SEGMENT_TREE_HPP #line 8 "include/data_structure/segment_tree.hpp" #include <cassert> #line 11 "include/data_structure/segment_tree.hpp" #include <limits> #include <string> #include <type_traits> #include <vector> #ifndef CP_LIBRARY_WARN # if (CP_LIBRARY_DEBUG_LEVEL >= 1) //! @brief Print warning message //! @note You can suppress the warning by uncommenting the following line # define CP_LIBRARY_WARN(msg) (std::cerr << (msg) << '\n') // # define CP_LIBRARY_WARN(msg) (static_cast<void>(0)) # else # define CP_LIBRARY_WARN(msg) (static_cast<void>(0)) # endif # define CP_LIBRARY_WARN_NOT_DEFINED #endif #ifndef CP_LIBRARY_ASSERT //! @brief Assert macro # define CP_LIBRARY_ASSERT(...) assert(__VA_ARGS__) # define CP_LIBRARY_ASSERT_NOT_DEFINED #endif namespace lib { namespace internal::segment_tree_hpp { template <typename Func, typename Arg> auto is_binary_op_of_impl(int) -> std::bool_constant<std::is_same_v<decltype(std::declval<Func>()(std::declval<Arg>(), std::declval<Arg>())), Arg>>; template <typename Func, typename Arg> auto is_binary_op_of_impl(...) -> std::false_type; //! @brief Check if Func(Arg, Arg) returns a value of type Arg. template <typename Func, typename Arg> [[maybe_unused]] constexpr bool is_binary_op_of_v = decltype(is_binary_op_of_impl<Func, Arg>(int {}))::value; } // namespace internal::segment_tree_hpp //! @brief Segment tree //! @tparam Elem element type. Watch out for overflows. //! @tparam Func binary op type. template <typename Elem = long long, typename Func = std::plus<>, std::enable_if_t<internal::segment_tree_hpp::is_binary_op_of_v<Func, Elem>, std::nullptr_t> = nullptr> class segment_tree { private: const int length; const Elem id; std::vector<Elem> data; Func binary_op; bool locked; //! @brief Propagate changes in the index-th element to its ancestors. //! @note Time complexity: O(log size) void propagate_impl(int index) { index += length; while (index > 0) { index >>= 1; data[index] = binary_op(data[index << 1], data[index << 1 | 1]); } } public: //! @brief Construct a vector of n zeroes. Default operation (sum) will be selected. //! @param n vector size explicit segment_tree(const int n) : length(n), id(0), data(length << 1, id), binary_op(), locked(false) {} //! @brief Construct a vector from an existing container. Default operation (sum) will be selected. //! @tparam Container container type (deduced from parameter). //! @param src Source (container) template <typename Container> explicit segment_tree(const Container& src) : length(static_cast<int>(std::size(src))), id(0), data(length << 1, id), binary_op(), locked(false) { std::copy(std::cbegin(src), std::cend(src), std::begin(data) + length); for (int i = length - 1; i > 0; --i) data[i] = binary_op(data[i << 1], data[i << 1 | 1]); } //! @brief Construct a vector of length n filled with init_vals. Default operation (sum) will be selected. //! @param n vector size //! @param init_val initial value for all elements segment_tree(const int n, const Elem init_val) : length(n), id(0), data(length << 1, id), binary_op(), locked(false) { std::fill(std::begin(data) + length, std::end(data), init_val); for (int i = length - 1; i > 0; --i) data[i] = binary_op(data[i << 1], data[i << 1 | 1]); } //! @brief Construct a vector of n zeroes, specifying a binary operation and its identity element. //! @param n vector size //! @param identity_element identity element of the binary operation //! @param binary_operation associative binary operation (sum, product, min, max, ...) segment_tree(const int n, const Elem identity_element, const Func& binary_operation) : length(n), id(identity_element), data(length << 1, id), binary_op(binary_operation), locked(false) {} //! @brief Construct a vector from an existing container, specifying a binary operation and its identity element. //! @tparam Container container type (deduced from parameter). //! @param src Source (container) //! @param identity_element identity element of the binary operation //! @param binary_operation associative binary operation (sum, product, min, max, ...) template <typename Container> segment_tree(const Container& src, const Elem identity_element, const Func& binary_operation) : length(static_cast<int>(std::size(src))), id(identity_element), data(length << 1, id), binary_op(binary_operation), locked(false) { std::copy(std::cbegin(src), std::cend(src), std::begin(data) + length); for (int i = length - 1; i > 0; --i) data[i] = binary_op(data[i << 1], data[i << 1 | 1]); } //! @brief Construct a vector of length n filled with init_vals, specifying a binary operation and its identity element. //! @param n vector size //! @param init_val initial value for all elements //! @param identity_element identity element of the binary operation //! @param binary_operation associative binary operation (sum, product, min, max, ...) segment_tree(const int n, const Elem init_val, const Elem identity_element, const Func& binary_operation) : length(n), id(identity_element), data(length << 1, id), binary_op(binary_operation), locked(false) { std::fill(std::begin(data) + length, std::end(data), init_val); for (int i = length - 1; i > 0; --i) data[i] = binary_op(data[i << 1], data[i << 1 | 1]); } //! @brief Construct a vector of n zeroes, specifying a binary operation and its identity element. //! @param n vector size //! @param identity_element identity element of the binary operation //! @param binary_operation associative binary operation (sum, product, min, max, ...) segment_tree(const int n, const Elem identity_element, Func&& binary_operation) : length(n), id(identity_element), data(length << 1, id), binary_op(std::move(binary_operation)), locked(false) {} //! @brief Construct a vector from an existing container, specifying a binary operation and its identity element. //! @tparam Container container type (deduced from parameter). //! @param src Source (container) //! @param identity_element identity element of the binary operation //! @param binary_operation associative binary operation (sum, product, min, max, ...) template <typename Container> segment_tree(const Container& src, const Elem identity_element, Func&& binary_operation) : length(static_cast<int>(std::size(src))), id(identity_element), data(length << 1, id), binary_op(std::move(binary_operation)), locked(false) { std::copy(std::cbegin(src), std::cend(src), std::begin(data) + length); for (int i = length - 1; i > 0; --i) data[i] = binary_op(data[i << 1], data[i << 1 | 1]); } //! @brief Construct a vector of n zeroes, specifying a binary operation and its identity element. //! @param n vector size //! @param identity_element identity element of the binary operation //! @param binary_operation associative binary operation (sum, product, min, max, ...) segment_tree(const int n, const Elem init_val, const Elem identity_element, Func&& binary_operation) : length(n), id(identity_element), data(length << 1, id), binary_op(std::move(binary_operation)), locked(false) { std::fill(std::begin(data) + length, std::end(data), init_val); for (int i = length - 1; i > 0; --i) data[i] = binary_op(data[i << 1], data[i << 1 | 1]); } ~segment_tree() { if (locked) CP_LIBRARY_WARN("Segment tree is destructed in a locked state."); } //! @return Vector size (length) [[nodiscard]] int size() const noexcept { return length; } //! @brief Add value to the index-th element. //! @param index index of the element to be added (0-indexed) //! @param value value to be added //! @note Time complexity: O(log size) if unlocked //! @note Time complexity: O(1) if locked void add(const int index, const Elem value) { CP_LIBRARY_ASSERT(0 <= index && index < length); data[index + length] = data[index + length] + value; if (!locked) propagate_impl(index); } //! @brief Set the value of the index-th element to value. //! @param index index (0-indexed) //! @param value value to be set //! @note Time complexity: O(log size) if unlocked //! @note Time complexity: O(1) if locked void set(const int index, const Elem value) { CP_LIBRARY_ASSERT(0 <= index && index < length); data[index + length] = value; if (!locked) propagate_impl(index); } //! @brief Get the value of the index-th element. //! @param index index (0-indexed) //! @note Time complexity: O(1) [[nodiscard]] Elem get(const int index) const { CP_LIBRARY_ASSERT(0 <= index && index < length); return data[index + length]; } //! @brief Calculate interval product. //! @param left lower limit of interval (0-indexed) //! @param right upper limit of interval (0-indexed) //! @return product (result of the specified binary operation) of the elements within [left, right) (half-open interval) //! @note Time complexity: O(log size) [[nodiscard]] Elem prod(int L, int R) const { CP_LIBRARY_ASSERT(!locked); CP_LIBRARY_ASSERT(0 <= L && L <= R && R <= length); L += length; R += length; Elem res_l = id, res_r = id; while (L < R) { if (L & 1) { res_l = binary_op(res_l, data[L]); ++L; } if (R & 1) res_r = binary_op(data[--R], res_r); L >>= 1; R >>= 1; } return binary_op(res_l, res_r); } //! @brief Calculate product of all elements. //! @param left lower limit of interval (0-indexed) //! @param right upper limit of interval (0-indexed) //! @return product (result of the specified binary operation) of all elements //! @note Time complexity: O(1) [[nodiscard]] Elem all_prod() const { CP_LIBRARY_ASSERT(!locked); return data[1]; } //! @warning You need to call this function ONLY IF you use lock()/unlock() function. //! @brief Propagate changes in the index-th element to its ancestors. //! @note Time complexity: O(log size) void propagate(int index) { CP_LIBRARY_ASSERT(locked); CP_LIBRARY_ASSERT(0 <= index && index < length); propagate_impl(index); } //! @warning You need to call this function ONLY IF you use lock()/unlock() function. //! @brief Propagate changes of all elements to the ancestors. //! @note Time complexity: O(size) void propagate_all() { CP_LIBRARY_ASSERT(locked); for (int i = length - 1; i > 0; --i) data[i] = binary_op(data[i << 1], data[i << 1 | 1]); } //! @warning You need to call this function ONLY IF you use lock()/unlock() function. //! @brief Propagate changes of all elements to the ancestors and resume automatic propagation. //! @note Time complexity: O(size) void propagate_all_and_unlock() { propagate_all(); unlock(); } //! @warning You can call this function only if you can promise not to call prod()/all_prod() until you call unlock(). //! @brief Stop automatic propagation on element changes. //! @note Time complexity: O(1) void lock() { CP_LIBRARY_ASSERT(!locked); locked = true; } //! @warning You can call this function only if this segment tree is locked. //! @warning This function will not perform propagation. You need to call propagate()/propagate_all() manually. //! @brief Resume automatic propagation on element changes. //! @note Time complexity: O(1) void unlock() { CP_LIBRARY_ASSERT(locked); locked = false; } //! @warning You need to call this function ONLY IF you use lock()/unlock() function. //! @return Whether the automatic propagation is stopped. //! @note Time complexity: O(1) [[nodiscard]] bool is_locked() const { return locked; } void debug_print([[maybe_unused]] const std::string& name = "", [[maybe_unused]] std::ostream& os = std::cerr) const { #if (CP_LIBRARY_DEBUG_LEVEL >= 1) if (!name.empty()) os << name << ": "; os << "val [ "; for (int i = 0; i < size(); ++i) os << get(i) << ' '; os << "]\n"; if (!name.empty()) os << std::string(std::size(name) + 2, ' '); os << "prod [ "; if (locked) os << "cannot display since range product query is locked "; else for (int i = 0; i <= size(); ++i) os << prod(0, i) << ' '; os << "]\n"; #endif } }; namespace internal::segment_tree_hpp { template <typename Tp> [[maybe_unused]] constexpr bool is_segment_tree_v = false; template <typename Elem, typename Func> [[maybe_unused]] constexpr bool is_segment_tree_v<segment_tree<Elem, Func>> = true; } // namespace internal::segment_tree_hpp //! @brief Utility class to automatically call lock() in constructor and propagate_all_and_unlock() in destructor. template <typename Tp, std::enable_if_t<internal::segment_tree_hpp::is_segment_tree_v<Tp>, std::nullptr_t> = nullptr> class no_range_query_in_this_scope { private: Tp& target_segtree; public: //! @brief Lock segment tree by calling lock(). //! @param segtree target segment tree //! @note Time complexity: O(1) explicit no_range_query_in_this_scope(Tp& segtree) : target_segtree(segtree) { target_segtree.lock(); } //! @brief Unlock segment tree and apply all changes by calling propagate_all_and_unlock(). //! @note Time complexity: O(size of target segment tree) ~no_range_query_in_this_scope() { target_segtree.propagate_all_and_unlock(); } }; } // namespace lib #ifdef CP_LIBRARY_WARN_NOT_DEFINED # undef CP_LIBRARY_WARN # undef CP_LIBRARY_WARN_NOT_DEFINED # ifdef CP_LIBRARY_WARN # undef CP_LIBRARY_WARN # endif #endif #ifdef CP_LIBRARY_ASSERT_NOT_DEFINED # undef CP_LIBRARY_ASSERT # undef CP_LIBRARY_ASSERT_NOT_DEFINED #endif #endif // CP_LIBRARY_SEGMENT_TREE_HPP #line 8 "test/data_structure/segment_tree/2.test.cpp" int main() { std::ios_base::sync_with_stdio(false); std::cin.tie(nullptr); int N, Q; std::cin >> N >> Q; lib::segment_tree<int, std::bit_xor<>> tree(N); { lib::no_range_query_in_this_scope query_lock(tree); for (int i = 0; i < N; ++i) { int buf; std::cin >> buf; tree.set(i, buf); } } while (Q--) { int t, x, y; std::cin >> t >> x >> y; --x; if (t == 1) tree.set(x, tree.get(x) ^ y); else std::cout << tree.prod(x, y) << '\n'; } }