From 4f8f929242a0cc1442a5b959773b8a6999243f55 Mon Sep 17 00:00:00 2001 From: ZhuangYumin Date: Thu, 18 Apr 2024 18:38:55 +0800 Subject: [PATCH] 20240418 --- ACMOJ-1335.cpp | 818 ++++++++++++++++++++++++++++++++++++++ ACMOJ-1381.cpp | 94 +++++ ACMOJ-1477.cpp | 29 ++ ACMOJ-1507.cpp | 28 ++ ACMOJ-1812.cpp | 100 +++++ ACMOJ-2112.cpp | 29 ++ ACMOJ-2121.cpp | 84 ++++ ACMOJ-2122.cpp | 81 ++++ ACMOJ-2132.cpp | 316 +++++++++++++++ ACMOJ-2133.cpp | 61 +++ ACMOJ-2139.cpp | 144 +++++++ ACMOJ-2140.cpp | 106 +++++ ACMOJ-2147.cpp | 66 +++ ACMOJ-2148.cpp | 107 +++++ ACMOJ-2163.cpp | 36 ++ ACMOJ-2165.cpp | 59 +++ ACMOJ-2178.cpp | 92 +++++ ACMOJ-2179.cpp | 78 ++++ ACMOJ-2180.cpp | 41 ++ ACMOJ-2181.cpp | 1039 ++++++++++++++++++++++++++++++++++++++++++++++++ 20 files changed, 3408 insertions(+) create mode 100644 ACMOJ-1335.cpp create mode 100644 ACMOJ-1381.cpp create mode 100644 ACMOJ-1477.cpp create mode 100644 ACMOJ-1507.cpp create mode 100644 ACMOJ-1812.cpp create mode 100644 ACMOJ-2112.cpp create mode 100644 ACMOJ-2121.cpp create mode 100644 ACMOJ-2122.cpp create mode 100644 ACMOJ-2132.cpp create mode 100644 ACMOJ-2133.cpp create mode 100644 ACMOJ-2139.cpp create mode 100644 ACMOJ-2140.cpp create mode 100644 ACMOJ-2147.cpp create mode 100644 ACMOJ-2148.cpp create mode 100644 ACMOJ-2163.cpp create mode 100644 ACMOJ-2165.cpp create mode 100644 ACMOJ-2178.cpp create mode 100644 ACMOJ-2179.cpp create mode 100644 ACMOJ-2180.cpp create mode 100644 ACMOJ-2181.cpp diff --git a/ACMOJ-1335.cpp b/ACMOJ-1335.cpp new file mode 100644 index 0000000..80cb8d7 --- /dev/null +++ b/ACMOJ-1335.cpp @@ -0,0 +1,818 @@ +#include +#ifndef SJTU_VECTOR_HPP +#define SJTU_VECTOR_HPP + +#include +#include +#include +#include +#include + +namespace sjtu { +/** + * a data container like std::vector + * store data in a successive memory and support random access. + */ +template +class vector { + static std::allocator alloc; + size_t allocated_length; + size_t current_length; + T *raw_beg, *raw_end; + + public: + /** + * you can see RandomAccessIterator at CppReference for help. + */ + class const_iterator; + class iterator { + // The following code is written for the C++ type_traits library. + // Type traits is a C++ feature for describing certain properties of a type. + // For instance, for an iterator, iterator::value_type is the type that the + // iterator points to. + // STL algorithms and containers may use these type_traits (e.g. the + // following typedef) to work properly. In particular, without the following + // code, + // @code{std::sort(iter, iter1);} would not compile. + // See these websites for more information: + // https://en.cppreference.com/w/cpp/header/type_traits + // About value_type: + // https://blog.csdn.net/u014299153/article/details/72419713 About + // iterator_category: https://en.cppreference.com/w/cpp/iterator + friend class vector; + + public: + using difference_type = std::ptrdiff_t; + using value_type = T; + using pointer = T *; + using reference = T &; + using iterator_category = std::random_access_iterator_tag; + + private: + vector *domain; + T *raw_pointer; + iterator(vector *domain, T *raw_pointer) + : domain(domain), raw_pointer(raw_pointer) {} + + public: + /** + * return a new iterator which pointer n-next elements + * as well as operator- + */ + iterator operator+(const int &n) const { + iterator temp = *this; + temp.raw_pointer += n; + return temp; + } + iterator operator-(const int &n) const { + iterator temp = *this; + temp.raw_pointer -= n; + return temp; + } + // return the distance between two iterators, + // if these two iterators point to different vectors, throw + // invaild_iterator. + int operator-(const iterator &rhs) const { + return raw_pointer - rhs.raw_pointer; + } + iterator &operator+=(const int &n) { + raw_pointer += n; + return *this; + } + iterator &operator-=(const int &n) { + raw_pointer -= n; + return *this; + } + /** + * TODO iter++ + */ + iterator operator++(int) { + iterator temp = *this; + raw_pointer++; + return temp; + } + /** + * TODO ++iter + */ + iterator &operator++() { + raw_pointer++; + return *this; + } + /** + * TODO iter-- + */ + iterator operator--(int) { + iterator temp = *this; + raw_pointer--; + return temp; + } + /** + * TODO --iter + */ + iterator &operator--() { + raw_pointer--; + return *this; + } + /** + * TODO *it + */ + T &operator*() const { return *raw_pointer; } + /** + * a operator to check whether two iterators are same (pointing to the same + * memory address). + */ + bool operator==(const iterator &rhs) const { + return raw_pointer == rhs.raw_pointer; + } + bool operator==(const const_iterator &rhs) const { + return raw_pointer == rhs.raw_pointer; + } + /** + * some other operator for iterator. + */ + bool operator!=(const iterator &rhs) const { + return raw_pointer != rhs.raw_pointer; + } + bool operator!=(const const_iterator &rhs) const { + return raw_pointer != rhs.raw_pointer; + } + }; + /** + * TODO + * has same function as iterator, just for a const object. + */ + class const_iterator { + friend class vector; + + public: + using difference_type = std::ptrdiff_t; + using value_type = T; + using pointer = T *; + using reference = T &; + using iterator_category = std::random_access_iterator_tag; + + private: + const vector *domain; + const T *raw_pointer; + inline const_iterator(const vector *domain, const T *raw_pointer) + : domain(domain), raw_pointer(raw_pointer) {} + + public: + /** + * return a new iterator which pointer n-next elements + * as well as operator- + */ + const_iterator operator+(const int &n) const { + const_iterator temp = *this; + temp.raw_pointer += n; + return temp; + } + const_iterator operator-(const int &n) const { + const_iterator temp = *this; + temp.raw_pointer -= n; + return temp; + } + // return the distance between two iterators, + // if these two iterators point to different vectors, throw + // invaild_iterator. + int operator-(const const_iterator &rhs) const { + return raw_pointer - rhs.raw_pointer; + } + const_iterator &operator+=(const int &n) { + raw_pointer += n; + return *this; + } + const_iterator &operator-=(const int &n) { + raw_pointer -= n; + return *this; + } + /** + * TODO iter++ + */ + const_iterator operator++(int) { + const_iterator temp = *this; + raw_pointer++; + return temp; + } + /** + * TODO ++iter + */ + const_iterator &operator++() { + raw_pointer++; + return *this; + } + /** + * TODO iter-- + */ + const_iterator operator--(int) { + const_iterator temp = *this; + raw_pointer--; + return temp; + } + /** + * TODO --iter + */ + const_iterator &operator--() { + raw_pointer--; + return *this; + } + /** + * TODO *it + */ + const T &operator*() const { return *raw_pointer; } + /** + * a operator to check whether two iterators are same (pointing to the same + * memory address). + */ + bool operator==(const iterator &rhs) const { + return raw_pointer == rhs.raw_pointer; + } + bool operator==(const const_iterator &rhs) const { + return raw_pointer == rhs.raw_pointer; + } + /** + * some other operator for iterator. + */ + bool operator!=(const iterator &rhs) const { + return raw_pointer != rhs.raw_pointer; + } + bool operator!=(const const_iterator &rhs) const { + return raw_pointer != rhs.raw_pointer; + } + }; + /** + * TODO Constructs + * At least two: default constructor, copy constructor + */ + vector() { + raw_beg = alloc.allocate(1); + raw_end = raw_beg; + allocated_length = 1; + current_length = 0; + } + vector(const vector &other) { + raw_beg = alloc.allocate(other.allocated_length); + raw_end = raw_beg + other.current_length; + allocated_length = other.allocated_length; + current_length = other.current_length; + for (size_t i = 0; i < current_length; ++i) { + std::allocator_traits::construct(alloc, raw_beg + i, + other.raw_beg[i]); + } + } + vector(vector &&other) noexcept { + raw_beg = other.raw_beg; + raw_end = other.raw_end; + allocated_length = other.allocated_length; + current_length = other.current_length; + other.raw_beg = nullptr; + other.raw_end = nullptr; + other.allocated_length = 0; + other.current_length = 0; + } + ~vector() { + if (raw_beg != nullptr) { + for (size_t i = 0; i < current_length; ++i) { + std::allocator_traits::destroy(alloc, raw_beg + i); + } + alloc.deallocate(raw_beg, allocated_length); + } + } + /** + * TODO Assignment operator + */ + vector &operator=(const vector &other) { + if (this == &other) return *this; + if (raw_beg != nullptr) { + for (size_t i = 0; i < current_length; ++i) { + std::allocator_traits::destroy(alloc, raw_beg + i); + } + alloc.deallocate(raw_beg, allocated_length); + } + raw_beg = alloc.allocate(other.allocated_length); + raw_end = raw_beg + other.current_length; + allocated_length = other.allocated_length; + current_length = other.current_length; + for (size_t i = 0; i < current_length; ++i) { + std::allocator_traits::construct(alloc, raw_beg + i, + other.raw_beg[i]); + } + return *this; + } + vector &operator=(vector &&other) noexcept { + if (this == &other) return *this; + if (raw_beg != nullptr) { + for (size_t i = 0; i < current_length; ++i) { + std::allocator_traits::destroy(alloc, raw_beg + i); + } + alloc.deallocate(raw_beg, allocated_length); + } + raw_beg = other.raw_beg; + raw_end = other.raw_end; + allocated_length = other.allocated_length; + current_length = other.current_length; + other.raw_beg = nullptr; + other.raw_end = nullptr; + other.allocated_length = 0; + other.current_length = 0; + return *this; + } + /** + * assigns specified element with bounds checking + * throw index_out_of_bound if pos is not in [0, size) + */ + T &at(const size_t &pos) { return raw_beg[pos]; } + const T &at(const size_t &pos) const { return raw_beg[pos]; } + /** + * assigns specified element with bounds checking + * throw index_out_of_bound if pos is not in [0, size) + * !!! Pay attentions + * In STL this operator does not check the boundary but I want you to do. + */ + T &operator[](const size_t &pos) { return raw_beg[pos]; } + const T &operator[](const size_t &pos) const { return raw_beg[pos]; } + /** + * access the first element. + * throw container_is_empty if size == 0 + */ + const T &front() const { return raw_beg[0]; } + /** + * access the last element. + * throw container_is_empty if size == 0 + */ + const T &back() const { return raw_end[-1]; } + /** + * returns an iterator to the beginning. + */ + iterator begin() { return iterator(this, raw_beg); } + const_iterator cbegin() const { return const_iterator(this, raw_beg); } + /** + * returns an iterator to the end. + */ + iterator end() { return iterator(this, raw_end); } + const_iterator cend() const { return const_iterator(this, raw_end); } + /** + * checks whether the container is empty + */ + bool empty() const { return current_length == 0; } + /** + * returns the number of elements + */ + size_t size() const { return current_length; } + /** + * clears the contents + */ + void clear() { + if (raw_beg != nullptr) { + for (size_t i = 0; i < current_length; ++i) { + std::allocator_traits::destroy(alloc, raw_beg + i); + } + alloc.deallocate(raw_beg, allocated_length); + } + raw_beg = alloc.allocate(1); + raw_end = raw_beg; + allocated_length = 1; + current_length = 0; + } + /** + * inserts value before pos + * returns an iterator pointing to the inserted value. + */ + iterator insert(iterator pos, const T &value) { + if (current_length == allocated_length) { + size_t new_allocated_length = allocated_length * 2; + T *new_raw_beg = alloc.allocate(new_allocated_length); + pos.raw_pointer = new_raw_beg + (pos.raw_pointer - raw_beg); + for (size_t i = 0; i < current_length; ++i) { + std::allocator_traits::construct( + alloc, new_raw_beg + i, std::move(raw_beg[i])); + std::allocator_traits::destroy(alloc, raw_beg + i); + } + alloc.deallocate(raw_beg, allocated_length); + raw_beg = new_raw_beg; + raw_end = raw_beg + current_length; + allocated_length = new_allocated_length; + } + for (T *i = raw_end; i != pos.raw_pointer; --i) { + std::allocator_traits::construct(alloc, i, + std::move(*(i - 1))); + std::allocator_traits::destroy(alloc, i - 1); + } + std::allocator_traits::construct(alloc, pos.raw_pointer, + value); + raw_end++; + current_length++; + return pos; + } + /** + * inserts value at index ind. + * after inserting, this->at(ind) == value + * returns an iterator pointing to the inserted value. + * throw index_out_of_bound if ind > size (in this situation ind can be size + * because after inserting the size will increase 1.) + */ + iterator insert(const size_t &ind, const T &value) { + if (current_length == allocated_length) { + size_t new_allocated_length = allocated_length * 2; + T *new_raw_beg = alloc.allocate(new_allocated_length); + for (size_t i = 0; i < current_length; ++i) { + alloc.construct(new_raw_beg + i, std::move(raw_beg[i])); + alloc.destroy(raw_beg + i); + } + alloc.deallocate(raw_beg, allocated_length); + raw_beg = new_raw_beg; + raw_end = raw_beg + current_length; + allocated_length = new_allocated_length; + } + for (T *i = raw_end; i != raw_beg + ind; --i) { + alloc.construct(i, std::move(*(i - 1))); + alloc.destroy(i - 1); + } + alloc.construct(raw_beg + ind, value); + raw_end++; + current_length++; + return iterator(this, raw_beg + ind); + } + /** + * removes the element at pos. + * return an iterator pointing to the following element. + * If the iterator pos refers the last element, the end() iterator is + * returned. + */ + iterator erase(iterator pos) { + for (T *i = pos.raw_pointer; i != raw_end - 1; ++i) { + std::allocator_traits::construct(alloc, i, + std::move(*(i + 1))); + std::allocator_traits::destroy(alloc, i + 1); + } + raw_end--; + current_length--; + if (current_length != 0 && current_length <= allocated_length / 4) { + size_t new_allocated_length = allocated_length / 2; + T *new_raw_beg = alloc.allocate(new_allocated_length); + for (size_t i = 0; i < current_length; ++i) { + std::allocator_traits::construct( + alloc, new_raw_beg + i, std::move(raw_beg[i])); + std::allocator_traits::destroy(alloc, raw_beg + i); + } + alloc.deallocate(raw_beg, allocated_length); + raw_beg = new_raw_beg; + raw_end = raw_beg + current_length; + allocated_length = new_allocated_length; + } + return pos; + } + /** + * removes the element with index ind. + * return an iterator pointing to the following element. + * throw index_out_of_bound if ind >= size + */ + iterator erase(const size_t &ind) { + for (T *i = raw_beg + ind; i != raw_end - 1; ++i) { + alloc.construct(i, std::move(*(i + 1))); + alloc.destroy(i + 1); + } + raw_end--; + current_length--; + if (current_length != 0 && current_length <= allocated_length / 4) { + size_t new_allocated_length = allocated_length / 2; + T *new_raw_beg = alloc.allocate(new_allocated_length); + for (size_t i = 0; i < current_length; ++i) { + alloc.construct(new_raw_beg + i, std::move(raw_beg[i])); + alloc.destroy(raw_beg + i); + } + alloc.deallocate(raw_beg, allocated_length); + raw_beg = new_raw_beg; + raw_end = raw_beg + current_length; + allocated_length = new_allocated_length; + } + return iterator(this, raw_beg + ind); + } + /** + * adds an element to the end. + */ + void push_back(const T &value) { + if (current_length == allocated_length) [[unlikely]] { + size_t new_allocated_length = allocated_length * 2; + T *new_raw_beg = alloc.allocate(new_allocated_length); + for (size_t i = 0; i < current_length; ++i) { + std::allocator_traits::construct( + alloc, new_raw_beg + i, std::move(raw_beg[i])); + std::allocator_traits::destroy(alloc, raw_beg + i); + } + alloc.deallocate(raw_beg, allocated_length); + raw_beg = new_raw_beg; + raw_end = raw_beg + current_length; + allocated_length = new_allocated_length; + } + std::allocator_traits::construct(alloc, raw_end, value); + raw_end++; + current_length++; + } + /** + * remove the last element from the end. + * throw container_is_empty if size() == 0 + */ + void pop_back() { + std::allocator_traits::destroy(alloc, raw_end - 1); + raw_end--; + current_length--; + if (current_length != 0 && current_length <= allocated_length / 4) + [[unlikely]] { + size_t new_allocated_length = allocated_length / 2; + T *new_raw_beg = alloc.allocate(new_allocated_length); + for (size_t i = 0; i < current_length; ++i) { + std::allocator_traits::construct( + alloc, new_raw_beg + i, std::move(raw_beg[i])); + std::allocator_traits::destroy(alloc, raw_beg + i); + } + alloc.deallocate(raw_beg, allocated_length); + raw_beg = new_raw_beg; + raw_end = raw_beg + current_length; + allocated_length = new_allocated_length; + } + } +}; +template +std::allocator vector::alloc; + +} // namespace sjtu + +#endif +typedef unsigned long long hash_t; +static inline hash_t Hash(std::string str) noexcept { + /* Reference: http://xorshift.di.unimi.it/splitmix64.c */ + static const std::string salt1 = "23af0j29d"; + static const std::string salt2 = "09dkl020"; + constexpr static char inner_salt[17] = "si9aW@zl#2$3%4^!"; + str = salt1 + str + salt2; + hash_t ret = 0; + int i = 0; + for (; i + 8 <= str.length(); i += 8) { + ret ^= *reinterpret_cast(str.c_str() + i); + ret ^= *reinterpret_cast(inner_salt + (i & 15)); + ret += 0x9e3779b97f4a7c15; + ret = (ret ^ (ret >> 30)) * 0xbf58476d1ce4e5b9; + ret = (ret ^ (ret >> 27)) * 0x94d049bb133111eb; + ret ^= ret >> 31; + } + for (; i < str.length(); ++i) { + ret ^= str[i]; + ret ^= inner_salt[i & 15]; + ret += 0x9e3779b97f4a7c15; + ret = (ret ^ (ret >> 30)) * 0xbf58476d1ce4e5b9; + ret = (ret ^ (ret >> 27)) * 0x94d049bb133111eb; + ret ^= ret >> 31; + } + return ret; +} + +namespace sjtu { +template +class unordered_map { + +}; +// implementation of unordered_map for Key = std::string +template +class unordered_map { + static const size_t kMaxBucketSize = 1 << 10; + struct Node { + std::string key; + T value; + Node *next; + Node() : next(nullptr) {} + Node(const std::string &key, const T &value, Node *next = nullptr) + : key(key), value(value), next(next) {} + }; + Node *buckets[kMaxBucketSize]; + size_t bucket_size; + size_t element_size; + + public: + unordered_map() : bucket_size(kMaxBucketSize), element_size(0) { + for (size_t i = 0; i < kMaxBucketSize; ++i) { + buckets[i] = nullptr; + } + } + ~unordered_map() { + for (size_t i = 0; i < kMaxBucketSize; ++i) { + Node *cur = buckets[i]; + while (cur != nullptr) { + Node *temp = cur; + cur = cur->next; + delete temp; + } + } + } + T &operator[](const std::string &key) { + size_t hash = Hash(key) & (kMaxBucketSize - 1); + Node *cur = buckets[hash]; + while (cur != nullptr) { + if (cur->key == key) return cur->value; + cur = cur->next; + } + cur = new Node(key, T(), buckets[hash]); + buckets[hash] = cur; + element_size++; + return cur->value; + } + T &at(const std::string &key) { + size_t hash = Hash(key) & (kMaxBucketSize - 1); + Node *cur = buckets[hash]; + while (cur != nullptr) { + if (cur->key == key) return cur->value; + cur = cur->next; + } + throw std::out_of_range("Key not found"); + } + const T &at(const std::string &key) const { + size_t hash = Hash(key) & (kMaxBucketSize - 1); + Node *cur = buckets[hash]; + while (cur != nullptr) { + if (cur->key == key) return cur->value; + cur = cur->next; + } + throw std::out_of_range("Key not found"); + } + size_t count(const std::string &key) const { + size_t hash = Hash(key) & (kMaxBucketSize - 1); + Node *cur = buckets[hash]; + while (cur != nullptr) { + if (cur->key == key) return 1; + cur = cur->next; + } + return 0; + } + void erase(const std::string &key) { + size_t hash = Hash(key) & (kMaxBucketSize - 1); + Node *cur = buckets[hash]; + if (cur == nullptr) return; + if (cur->key == key) { + buckets[hash] = cur->next; + delete cur; + element_size--; + return; + } + while (cur->next != nullptr) { + if (cur->next->key == key) { + Node *temp = cur->next; + cur->next = cur->next->next; + delete temp; + element_size--; + return; + } + cur = cur->next; + } + } + void clear() { + for (size_t i = 0; i < kMaxBucketSize; ++i) { + Node *cur = buckets[i]; + while (cur != nullptr) { + Node *temp = cur; + cur = cur->next; + delete temp; + } + buckets[i] = nullptr; + } + element_size = 0; + } + size_t size() const { return element_size; } + bool Have(const std::string &key) const { + size_t hash = Hash(key) & (kMaxBucketSize - 1); + Node *cur = buckets[hash]; + while (cur != nullptr) { + if (cur->key == key) return true; + cur = cur->next; + } + return false; + } +}; +} // namespace sjtu +class ClassType { + public: + enum ImportType { kPublicImport, kProtectedImport, kPrivateImport }; + enum StatusType { + kPublic = 4, + kProtected = 3, + kPrivate = 2, + kUnvisible = 1, + kNone = 0 + }; + void Import(ClassType &src, ImportType import_type) { + if (import_type == ImportType::kPublicImport) { + pub_anc.push_back(&src); + } else if (import_type == ImportType::kProtectedImport) { + prot_anc.push_back(&src); + } else { + priv_anc.push_back(&src); + } + } + + void AddElement(const std::string &name, StatusType status) { + elements[name] = status; + } + + StatusType QueryElement(const std::string &name) { + return DFSSearch(this, name); + } + + private: + static StatusType DFSSearch(ClassType *rt, const std::string name) { + StatusType res = StatusType::kNone; + if (rt->elements.Have(name)) res = rt->elements[name]; + for (int i = 0; i < rt->pub_anc.size(); i++) { + StatusType sub_res = DFSSearch(rt->pub_anc[i], name); + if (sub_res == StatusType::kPrivate) sub_res = StatusType::kUnvisible; + res = (sub_res > res) ? sub_res : res; + } + for (int i = 0; i < rt->prot_anc.size(); i++) { + StatusType sub_res = DFSSearch(rt->prot_anc[i], name); + if (sub_res == StatusType::kPrivate) sub_res = StatusType::kUnvisible; + if ((sub_res == StatusType::kPublic) || + (sub_res == StatusType::kProtected)) + sub_res = StatusType::kProtected; + res = (sub_res > res) ? sub_res : res; + } + for (int i = 0; i < rt->priv_anc.size(); i++) { + StatusType sub_res = DFSSearch(rt->priv_anc[i], name); + if (sub_res == StatusType::kPrivate) sub_res = StatusType::kUnvisible; + if ((sub_res == StatusType::kPublic) || + (sub_res == StatusType::kProtected)) + sub_res = StatusType::kPrivate; + res = (sub_res > res) ? sub_res : res; + } + return res; + } + + sjtu::unordered_map elements; + sjtu::vector pub_anc, prot_anc, priv_anc; +}; +int main() { +#ifdef local + freopen("pro.in", "r", stdin); +#endif // ifdef local + int n; + sjtu::unordered_map class_registery; + std::cin >> n; + for (int i = 0; i < n; i++) { + std::string name; + std::cin >> name; + class_registery[name]; + int k0; + std::cin >> k0; + for (int j = 0; j < k0; j++) { + std::string method, srcname; + std::cin >> method >> srcname; + if (method == "public") + class_registery[name].Import(class_registery[srcname], + ClassType::ImportType::kPublicImport); + else if (method == "private") + class_registery[name].Import(class_registery[srcname], + ClassType::ImportType::kPrivateImport); + else + class_registery[name].Import(class_registery[srcname], + ClassType::ImportType::kProtectedImport); + } + int k1; + std::cin >> k1; + for (int j = 0; j < k1; j++) { + std::string mode, element_name; + std::cin >> mode >> element_name; + if (mode == "public") + class_registery[name].AddElement(element_name, + ClassType::StatusType::kPublic); + else if (mode == "private") + class_registery[name].AddElement(element_name, + ClassType::StatusType::kPrivate); + else + class_registery[name].AddElement(element_name, + ClassType::StatusType::kProtected); + } + } + int m; + std::cin >> m; + for (int i = 0; i < m; i++) { + std::string class_name, element_name; + std::cin >> class_name >> element_name; + ClassType::StatusType stat = + class_registery[class_name].QueryElement(element_name); + switch (stat) { + case ClassType::StatusType::kNone: + std::cout << "None\n"; + break; + case ClassType::StatusType::kPrivate: + std::cout << "Private\n"; + break; + case ClassType::StatusType::kProtected: + std::cout << "Protected\n"; + break; + case ClassType::StatusType::kPublic: + std::cout << "Public\n"; + break; + case ClassType::StatusType::kUnvisible: + std::cout << "Can not Fetch\n"; + break; + } + } + return 0; +} \ No newline at end of file diff --git a/ACMOJ-1381.cpp b/ACMOJ-1381.cpp new file mode 100644 index 0000000..5fc7e5c --- /dev/null +++ b/ACMOJ-1381.cpp @@ -0,0 +1,94 @@ +#include +#include +#include +#include +using namespace std; +typedef long long LL; +typedef uint64_t hash_t; +static inline hash_t Hash(char *str, int len) noexcept { + /* Reference: http://xorshift.di.unimi.it/splitmix64.c */ + hash_t ret = 0; + static char inner_salt[17] = "si9aW@zl#2$3%4^!"; + int i = 0; + for (; i + 8 <= len; i += 8) { + ret ^= *reinterpret_cast(str + i); + ret ^= *reinterpret_cast(inner_salt + (i & 15)); + ret += 0x9e3779b97f4a7c15; + ret = (ret ^ (ret >> 30)) * 0xbf58476d1ce4e5b9; + ret = (ret ^ (ret >> 27)) * 0x94d049bb133111eb; + ret ^= ret >> 31; + } + for (; i < len; ++i) { + ret ^= str[i]; + ret ^= inner_salt[i & 15]; + ret += 0x9e3779b97f4a7c15; + ret = (ret ^ (ret >> 30)) * 0xbf58476d1ce4e5b9; + ret = (ret ^ (ret >> 27)) * 0x94d049bb133111eb; + ret ^= ret >> 31; + } + return ret; +} +const int kMaxN = 1005; +const int kMaxM = 1e5 + 10; +int n, m; +unordered_map wanted, cnt; +hash_t paragraph[kMaxM]; +int main() { +#ifdef local + freopen("pro.in", "r", stdin); +#endif + char tmp[15]; + scanf("%d", &n); + for (int i = 0; i < n; i++) { + scanf("%s", tmp); + wanted[Hash(tmp, strlen(tmp))] = 1; + } + scanf("%d", &m); + int count_needed = 0; + for (int i = 0; i < m; i++) { + scanf("%s", tmp); + paragraph[i] = Hash(tmp, strlen(tmp)); + if (wanted.find(paragraph[i]) != wanted.end() && + wanted[paragraph[i]] == 1) { + count_needed++; + wanted[paragraph[i]] = 2; + } + } + printf("%d\n", count_needed); + int L = 0, R = -1, current_have = 0; + while (current_have < count_needed) { + R++; + if (wanted.find(paragraph[R]) != wanted.end()) { + cnt[paragraph[R]]++; + if (cnt[paragraph[R]] == 1) current_have++; + } + } + while (L <= R) { + if (wanted.find(paragraph[L]) == wanted.end()) { + L++; + } else if (cnt[paragraph[L]] >= 2) { + cnt[paragraph[L]]--; + L++; + } else + break; + } + int res = R - L + 1; + while (R + 1 < m) { + R++; + if (wanted.find(paragraph[R]) != wanted.end()) { + cnt[paragraph[R]]++; + while (L <= R) { + if (wanted.find(paragraph[L]) == wanted.end()) { + L++; + } else if (cnt[paragraph[L]] >= 2) { + cnt[paragraph[L]]--; + L++; + } else + break; + } + res = min(res, R - L + 1); + } + } + printf("%d\n", res); + return 0; +} \ No newline at end of file diff --git a/ACMOJ-1477.cpp b/ACMOJ-1477.cpp new file mode 100644 index 0000000..01eee05 --- /dev/null +++ b/ACMOJ-1477.cpp @@ -0,0 +1,29 @@ +#include +#include +#include +#include +using namespace std; +const int kMaxN = 1e6 + 10; +char s[kMaxN]; +int len = 0; +int Next[kMaxN]; +int main() { +#ifdef local + freopen("pro.in", "r", stdin); +#endif + scanf("%s", s + 1); + len = strlen(s + 1); + for (int i = 2, j = 0; i <= len; i++) { + while (j > 0 && s[i] != s[j + 1]) j = Next[j]; + if (s[i] == s[j + 1]) j++; + Next[i] = j; + } + stack res; + for (int p = len; p > 0; p = Next[p]) res.push(p); + while(!res.empty()) + { + printf("%d\n",res.top()); + res.pop(); + } + return 0; +} \ No newline at end of file diff --git a/ACMOJ-1507.cpp b/ACMOJ-1507.cpp new file mode 100644 index 0000000..e15f75f --- /dev/null +++ b/ACMOJ-1507.cpp @@ -0,0 +1,28 @@ +#include +#include +#include +using namespace std; +typedef long long LL; +const int kMaxN = 1e6 + 10; +char S[kMaxN], T[kMaxN]; +int nxt[kMaxN]; +int main() { +#ifdef local + freopen("pro.in", "r", stdin); +#endif + scanf("%s%s", S + 1, T + 1); + int len_T = strlen(T + 1); + for (int i = 2, j = 0; i <= len_T; i++) { + while (j > 0 && T[j + 1] != T[i]) j = nxt[j]; + if (T[j + 1] == T[i]) j++; + nxt[i] = j; + } + int len_S = strlen(S + 1); + for (int i = 1, j = 0; i <= len_S; i++) { + while (j > 0 && (j == len_T || T[j + 1] != S[i])) j = nxt[j]; + if (T[j + 1] == S[i]) j++; + if (j == len_T) printf("%d\n", i - len_T + 1); + } + for (int i = 1; i <= len_T; i++) printf("%d ", nxt[i]); + return 0; +} \ No newline at end of file diff --git a/ACMOJ-1812.cpp b/ACMOJ-1812.cpp new file mode 100644 index 0000000..680d154 --- /dev/null +++ b/ACMOJ-1812.cpp @@ -0,0 +1,100 @@ +#include +#include +#include +#include +using namespace std; +template +void MergeSort(T *beg, T *end, bool (*cmp)(const T &, const T &)) { + if (end - beg <= 1) return; + size_t len = end - beg; + T *mid = beg + (len >> 1); + MergeSort(beg, mid, cmp); + MergeSort(mid, end, cmp); + T *tmp = new T[len]; + T *cur_tmp = tmp, *cur_L = beg, *cur_R = mid; + while ((cur_L < mid) && (cur_R < end)) { + if (cmp(*cur_L, *cur_R)) + *(cur_tmp++) = *(cur_L++); + else + *(cur_tmp++) = *(cur_R++); + } + while (cur_L < mid) *(cur_tmp++) = *(cur_L++); + while (cur_R < end) *(cur_tmp++) = *(cur_R++); + cur_tmp = tmp; + T *cur_dst = beg; + while (cur_dst < end) *(cur_dst++) = *(cur_tmp++); + delete[] tmp; +} +typedef long long LL; +typedef long double LDB; +const int kMaxN = 5e4 + 10; +const int kMaxM = 1e5 + 10; +int n, m, K; +struct Edge { + int u, v, w; + bool is_white; +} edge[kMaxM]; +int penalty_for_white; +bool Cmp(const Edge &A, const Edge &B) { + int wa = (A.is_white ? A.w + penalty_for_white : A.w); + int wb = (B.is_white ? B.w + penalty_for_white : B.w); + if (wa == wb) return (int)A.is_white > (int)B.is_white; + return wa < wb; +} +int fa[kMaxN]; +inline int ff(int u) { + int x = u, y; + while (fa[u] != u) u = fa[u]; + while (x != u) { + y = fa[x]; + fa[x] = u; + x = y; + } + return u; +} +void Calc(LL &res, int &white_used_count) { + white_used_count = 0; + res = 0; + MergeSort(edge, edge + m, Cmp); + for (int i = 0; i <= n; i++) fa[i] = i; + for (int i = 0; i < m; i++) { + int u = edge[i].u; + int v = edge[i].v; + int w = edge[i].is_white ? edge[i].w + penalty_for_white : edge[i].w; + if (ff(u) == ff(v)) continue; + fa[ff(u)] = ff(v); + if (edge[i].is_white) white_used_count++; + res += w; + } +} +int main() { +#ifdef local + freopen("pro.in", "r", stdin); +#endif + scanf("%d%d%d", &n, &m, &K); + for (int i = 0; i < m; i++) { + int u, v, w, col; + scanf("%d%d%d%d", &u, &v, &w, &col); + edge[i] = Edge{u, v, w, bool(col == 0)}; + } + int L = -110, R = 110; + LL ans = 0x3f3f3f3f3f3f3f3f; + while (L < R) { + int M = (L + R) >> 1; + penalty_for_white = M; + LL res; + int white_used_count; + Calc(res, white_used_count); + // printf("mid=%d flag=%d\n",M,int(white_used_count >= K)); + if (white_used_count >= K) { + ans = res - K * (LL)penalty_for_white; + // printf("ans=%lld mid=%d\n",ans,M); + L = M + 1; + } else if (white_used_count < K) { + R = M; + } + } + if (0x3f3f3f3f3f3f3f3f == ans) ans = -1; + printf("%lld\n", ans); + return 0; +} \ No newline at end of file diff --git a/ACMOJ-2112.cpp b/ACMOJ-2112.cpp new file mode 100644 index 0000000..c566c64 --- /dev/null +++ b/ACMOJ-2112.cpp @@ -0,0 +1,29 @@ +#include +#include +#include +#include +using namespace std; +const int kMaxN = 4e6 + 10; +char s[kMaxN], s_reverse[kMaxN]; +int len = 0; +int Next[kMaxN]; +int main() { +#ifdef local + freopen("pro.in", "r", stdin); +#endif + scanf("%s", s + 1); + len = strlen(s + 1); + for (int i = 1; i <= len; i++) s_reverse[i] = s[len + 1 - i]; + for (int i = 2, j = 0; i <= len; i++) { + while (j > 0 && s_reverse[i] != s_reverse[j + 1]) j = Next[j]; + if (s_reverse[i] == s_reverse[j + 1]) j++; + Next[i] = j; + } + int p = 0; + for (int i = 1; i <= len; i++) { + while (p > 0 && s[i] != s_reverse[p + 1]) p = Next[p]; + if (s[i] == s_reverse[p + 1]) p++; + } + printf("%d\n", len - p); + return 0; +} \ No newline at end of file diff --git a/ACMOJ-2121.cpp b/ACMOJ-2121.cpp new file mode 100644 index 0000000..c7ee88a --- /dev/null +++ b/ACMOJ-2121.cpp @@ -0,0 +1,84 @@ +#include +#include +#include +#include +using namespace std; +typedef long long LL; +typedef long double LDB; +const int kMaxN = (1 << 20) + 10; +int T; +char s[kMaxN]; +int z[kMaxN]; +int suf_cnt[26], pre_cnt[26]; +int tot_bucket[kMaxN]; +inline void Flip(char ch, int *cnt, int &occur) { + cnt[ch - 'a'] ^= 1; + if (cnt[ch - 'a']) + occur++; + else + occur--; +} +LL solve() { + int n = strlen(s); + memset(z, 0, sizeof(z)); + for (int i = 1, l = 0, r = 0; i < n; ++i) { + if (i <= r && z[i - l] < r - i + 1) { + z[i] = z[i - l]; + } else { + z[i] = max(0, r - i + 1); + while (i + z[i] < n && s[z[i]] == s[i + z[i]]) ++z[i]; + } + if (i + z[i] - 1 > r) l = i, r = i + z[i] - 1; + } + LL res = 0; + int even_A_tot = 0; + int odd_A_tot = 0; + memset(suf_cnt, 0, sizeof(suf_cnt)); + for (int i = 0; i < n; i++) suf_cnt[s[i] - 'a'] ^= 1; + int all_occur_tot = 0, suf_occur_tot = 0, pre_occur_tot = 0; + for (int i = 0; i < 26; i++) all_occur_tot += suf_cnt[i]; + memset(pre_cnt, 0, sizeof(pre_cnt)); + suf_occur_tot = all_occur_tot; + Flip(s[0], suf_cnt, suf_occur_tot); + memset(tot_bucket, 0, sizeof(tot_bucket)); + for (int i = 1; i <= n - 1; i++) { + int odd_C_tot = ceil((min(z[i], n - i - 1) / i + 1) / 2.0); + int even_C_tot = ((min(z[i], n - i - 1) / i + 1) / 2.0); + res += odd_A_tot * (LL)odd_C_tot; + res += even_A_tot * (LL)even_C_tot; + // printf("A(%d,%d)\n", odd_A_tot, odd_C_tot); + // printf("B(%d,%d)\n", even_A_tot, even_C_tot); + if (i == n - 1) break; + int old_suf_occur_tot = suf_occur_tot; + Flip(s[i], suf_cnt, suf_occur_tot); + // Flip(s[i - 1], pre_cnt, pre_occur_tot, tot_bucket); + pre_cnt[s[i - 1] - 'a'] ^= 1; + if (pre_cnt[s[i - 1] - 'a']) { + pre_occur_tot++; + } else { + pre_occur_tot--; + } + tot_bucket[pre_occur_tot]++; + if (pre_occur_tot <= old_suf_occur_tot) odd_A_tot++; + if (old_suf_occur_tot < suf_occur_tot) + odd_A_tot += tot_bucket[suf_occur_tot]; + else + odd_A_tot -= tot_bucket[old_suf_occur_tot]; + // printf("i=%d all_occur_tot=%d pre_occur_tot=%d suf_occur_tot=%d\n", i, + // all_occur_tot, pre_occur_tot, suf_occur_tot); + // odd_A_tot += (pre_occur_tot <= suf_occur_tot ? 1 : 0); + even_A_tot += (pre_occur_tot <= all_occur_tot ? 1 : 0); + } + return res; +} +int main() { +#ifdef local + freopen("pro.in", "r", stdin); +#endif + scanf("%d", &T); + while (T-- > 0) { + scanf("%s", s); + printf("%lld\n", solve()); + } + return 0; +} \ No newline at end of file diff --git a/ACMOJ-2122.cpp b/ACMOJ-2122.cpp new file mode 100644 index 0000000..22a3d95 --- /dev/null +++ b/ACMOJ-2122.cpp @@ -0,0 +1,81 @@ +#include +#include +#include +#include +#include +using namespace std; +typedef long long LL; +typedef long double LDB; +const int kMaxN = 4e3 + 10; +struct Point { + int a, b, c; +}; +int ch[2][2][kMaxN][26], fa[2][kMaxN], len[2][kMaxN]; +bool vis[kMaxN][kMaxN]; +int tot[2] = {1, 1}, last[2] = {1, 1}; +char A[kMaxN], B[kMaxN]; +void InitSequenceMachine(char *s, int flag) { + for (int i = strlen(s + 1); i; --i) { + memcpy(ch[flag][0][i - 1], ch[flag][0][i], 104); + ch[flag][0][i - 1][s[i] - 'a'] = i; + } +} +void AddChar(int character, int string_flag) { + int p = last[string_flag], np = last[string_flag] = ++tot[string_flag]; + len[string_flag][np] = len[string_flag][p] + 1; + for (; p && !ch[string_flag][1][p][character]; p = fa[string_flag][p]) + ch[string_flag][1][p][character] = np; + if (!p) + fa[string_flag][np] = 1; + else { + int q = ch[string_flag][1][p][character]; + if (len[string_flag][q] == len[string_flag][p] + 1) + fa[string_flag][np] = q; + else { + int nq = ++tot[string_flag]; + len[string_flag][nq] = len[string_flag][p] + 1; + fa[string_flag][nq] = fa[string_flag][q]; + fa[string_flag][q] = fa[string_flag][np] = nq; + memcpy(ch[string_flag][1][nq], ch[string_flag][1][q], 104); + for (; p && ch[string_flag][1][p][character] == q; p = fa[string_flag][p]) + ch[string_flag][1][p][character] = nq; + } + } +} +void Solve(int flag1, int flag2) { + memset(vis, 0, sizeof(vis)); + queue q; + q.push((Point){flag1, flag2, 0}); + vis[flag1][flag2] = 1; + while (!q.empty()) { + Point now = q.front(); + q.pop(); + for (int i = 0; i < 26; ++i) + if (ch[0][flag1][now.a][i]) { + if (ch[1][flag2][now.b][i]) { + int a = ch[0][flag1][now.a][i], b = ch[1][flag2][now.b][i]; + if (!vis[a][b]) vis[a][b] = 1, q.push((Point){a, b, now.c + 1}); + } else { + printf("%d\n", now.c + 1); + return; + } + } + } + printf("-1\n"); +} +int main() { +#ifdef local + freopen("pro.in", "r", stdin); +#endif + scanf("%s", A + 1); + scanf("%s", B + 1); + InitSequenceMachine(A, 0); + InitSequenceMachine(B, 1); + for (char *p = A + 1; *p; p++) AddChar(*p - 'a', 0); + for (char *p = B + 1; *p; p++) AddChar(*p - 'a', 1); + Solve(1, 1); + Solve(1, 0); + Solve(0, 1); + Solve(0, 0); + return 0; +} \ No newline at end of file diff --git a/ACMOJ-2132.cpp b/ACMOJ-2132.cpp new file mode 100644 index 0000000..abda62d --- /dev/null +++ b/ACMOJ-2132.cpp @@ -0,0 +1,316 @@ +#include +#define unlikely(x) __builtin_expect(!!(x), 0) +struct char_reader { + FILE *f; + char *buf, *p1, *p2; + int size; + char_reader(FILE *fin, int bufsize = 1 << 16) { + f = fin; + size = bufsize; + p1 = p2 = 0; + buf = new char[size]; + } + ~char_reader() { delete[] buf; } + inline int operator()() { + return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, size, f), p1 == p2) + ? EOF + : *p1++; + } +}; +struct char_writer { + FILE *f; + char *buf, *p, *end; + int size; + char_writer(FILE *fout, int bufsize = 1 << 16) { + f = fout; + size = bufsize; + buf = new char[size]; + p = buf; + end = buf + bufsize; + } + ~char_writer() { + fwrite(buf, p - buf, 1, f); + delete[] buf; + } + inline char operator()(char ch) { + if (unlikely(end == p)) { + fwrite(buf, end - buf, 1, f); + p = buf; + } + return *p++ = ch; + } +}; +char_reader gch(stdin); +char_writer wch(stdout); +template +inline int read(T &t) { + bool f = false; + int ch; + while (ch = gch(), !((ch >= '0' && ch <= '9') || ch == '-')) { + if (ch == EOF) return 0; + } + t = 0; + if (ch == '-') f = true, ch = gch(); + t = ch ^ 48; + while (ch = gch(), ch >= '0' && ch <= '9') + t = (t << 3) + (t << 1) + (ch ^ 48); + if (f) t = -t; + return 1; +} +inline int read(char &c) { + c = 0; + int ch; + while (ch = gch(), (ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t')) { + if (ch == EOF) return 0; + } + c = ch; + return 1; +} +inline int read(char *s) { + int ch; + while (ch = gch(), (ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t')) { + if (ch == EOF) return 0; + } + *s++ = ch; + while (ch = gch(), + !(ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t') && ch != EOF) + *s++ = ch; + *s++ = 0; + return 1; +} +inline int read(const char *s) { return read((char *)s); } +inline int readline(char *s) { + int ch; + while (ch = gch(), (ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t')) { + if (ch == EOF) return 0; + } + *s++ = ch; + while (ch = gch(), !(ch == '\n' || ch == '\r') && ch != EOF) *s++ = ch; + *s++ = 0; + return 1; +} +inline int readline(const char *s) { return readline((char *)s); } +template +inline void write(T t) { + int stk[20], cnt = 0; + if (t == 0) { + wch('0'); + return; + } + if (t < 0) { + wch('-'); + t = -t; + } + while (t > 0) { + stk[cnt++] = t % 10; + t /= 10; + } + while (cnt) wch(stk[--cnt] + '0'); +} +inline void write(char t) { wch(t); } +inline void write(char *s) { + while (*s) wch(*s++); +} +inline void write(const char *s) { write((char *)s); } +#if __cplusplus >= 201103L +template +inline int read(T &t, Args &...args) { + return read(t) + read(args...); +} +template +inline void write(T t, Args... args) { + write(t); + write(args...); +} +#else +template +inline int read(A_t &a, B_t &b) { + return read(a) + read(b); +} +template +inline int read(A_t &a, B_t &b, C_t &c) { + return read(a) + read(b) + read(c); +} +template +inline int read(A_t &a, B_t &b, C_t &c, D_t &d) { + return read(a) + read(b) + read(c) + read(d); +} +template +inline void write(A_t a, B_t b) { + write(a); + write(b); +} +template +inline void write(A_t a, B_t b, C_t c) { + write(a); + write(b); + write(c); +} +template +inline void write(A_t a, B_t b, C_t c, D_t d) { + write(a); + write(b); + write(c); + write(d); +} +#endif +#include +#include +#include +#include +#include +using namespace std; +typedef long long LL; +namespace __SA_IS { +const int L_TYPE = 0; +const int S_TYPE = 1; +const int kMaxN = 3e5 + 10; +const int kMaxChar = 1e6; +int a[kMaxN * 2], sa[kMaxN * 2], typ[kMaxN * 2], c[kMaxChar * 2 + 5], + p[kMaxN * 2], sbuc[kMaxChar + 5], lbuc[kMaxChar + 5], name[kMaxN * 2]; + +inline int islms(int *typ, int i) { return !typ[i] && (i == 1 || typ[i - 1]); } + +int cmp(int *s, int *typ, int p, int q) { + do { + if (s[p] != s[q]) return 1; + p++; + q++; + } while (!islms(typ, p) && !islms(typ, q)); + return (!islms(typ, p) || !islms(typ, q) || s[p] != s[q]); +} + +void isort(int *s, int *sa, int *typ, int *c, int n, int m) { + int i; + for (lbuc[0] = sbuc[0] = c[0], i = 1; i <= m; i++) { + lbuc[i] = c[i - 1] + 1; + sbuc[i] = c[i]; + } + for (i = 1; i <= n; i++) + if (sa[i] > 1 && typ[sa[i] - 1]) sa[lbuc[s[sa[i] - 1]]++] = sa[i] - 1; + for (i = n; i >= 1; i--) + if (sa[i] > 1 && !typ[sa[i] - 1]) sa[sbuc[s[sa[i] - 1]]--] = sa[i] - 1; +} + +void build_sa(int *s, int *sa, int *typ, int *c, int *p, int n, int m) { + int i; + for (i = 0; i <= m; i++) c[i] = 0; + for (i = 1; i <= n; i++) c[s[i]]++; + for (i = 1; i <= m; i++) c[i] += c[i - 1]; + typ[n] = 0; + for (i = n - 1; i >= 1; i--) + if (s[i] < s[i + 1]) + typ[i] = 0; + else if (s[i] > s[i + 1]) + typ[i] = 1; + else + typ[i] = typ[i + 1]; + int cnt = 0; + for (i = 1; i <= n; i++) + if (!typ[i] && (i == 1 || typ[i - 1])) p[++cnt] = i; + for (i = 1; i <= n; i++) sa[i] = 0; + for (i = 0; i <= m; i++) sbuc[i] = c[i]; + for (i = 1; i <= cnt; i++) sa[sbuc[s[p[i]]]--] = p[i]; + isort(s, sa, typ, c, n, m); + int last = 0, t = -1, x; + for (i = 1; i <= n; i++) { + x = sa[i]; + if (!typ[x] && (x == 1 || typ[x - 1])) { + if (!last || cmp(s, typ, x, last)) + name[x] = ++t; + else + name[x] = t; + last = x; + } + } + for (i = 1; i <= cnt; i++) s[n + i] = name[p[i]]; + if (t < cnt - 1) + build_sa(s + n, sa + n, typ + n, c + m + 1, p + n, cnt, t); + else + for (i = 1; i <= cnt; i++) sa[n + s[n + i] + 1] = i; + for (i = 0; i <= m; i++) sbuc[i] = c[i]; + for (i = 1; i <= n; i++) sa[i] = 0; + for (i = cnt; i >= 1; i--) sa[sbuc[s[p[sa[n + i]]]]--] = p[sa[n + i]]; + isort(s, sa, typ, c, n, m); +} +} // namespace __SA_IS +void SA_IS(int *s, int n, int *sa, int *rk) { + using namespace __SA_IS; + for (int i = 1; i <= n; i++) a[i] = s[i]; + a[++n] = 0; + build_sa(a, sa, typ, c, p, n, kMaxChar); + n--; + for (int i = 1; i <= n; i++) sa[i] = sa[i + 1]; + for (int i = 1; i <= n; i++) rk[sa[i]] = i; +} +void computeHeight(int *s, int n, int *sa, int *rk, int *height) { + int k = 0; + for (int i = 1; i <= n; i++) { + if (rk[i] == 1) { + height[rk[i]] = 0; + continue; + } + if (k > 0) { k--; } + int j = sa[rk[i] - 1]; + while (i + k <= n && j + k <= n && s[i + k] == s[j + k]) { k++; } + height[rk[i]] = k; + } +} +const int kMaxN = 3e5 + 10; +int n; +int str[kMaxN << 2], sa[kMaxN << 2], rnk[kMaxN << 2], height[kMaxN], res[kMaxN]; +const int kInf = 0x3f3f3f3f; +int main() { +#ifdef local + freopen("pro.in", "r", stdin); +#endif + read(n); + for (int i = 1; i <= n; i++) read(str[i]); + SA_IS(str, n, sa, rnk); + computeHeight(str, n, sa, rnk, height); + vector sa2, height2; + sa2.push_back(-1); + height2.push_back(-1); + sa2.push_back(sa[1]); + height2.push_back(0); + int current_shared_length = kInf; + for (int i = 2; i <= n; i++) { + current_shared_length = min(current_shared_length, height[i]); + if (sa[i] < sa2.back()) { + sa2.push_back(sa[i]); + height2.push_back(current_shared_length); + current_shared_length = kInf; + } + } + vector> stk; + for (int i = sa2.size() - 1; i >= 1; i--) { + if (i == sa2.size() - 1) [[unlikely]] { + stk.push_back(make_pair(sa2[i], n + 1 - sa2[i])); + int L = 1; + if (i - 1 >= 1) L = n + 1 - sa2[i - 1] + 1; + for (int j = L; j <= n + 1 - sa2[i]; j++) res[j] = sa2[i]; + continue; + } + while (stk.size()) { + int h = height2[i + 1]; + if (stk.back().second < h) break; + if (stk.size() >= 2 && (stk.end() - 2)->second >= h) + stk.pop_back(); + else { + stk.back().second = h; + break; + } + } + stk.push_back(make_pair(sa2[i], n + 1 - sa2[i])); + int L = 1; + if (i - 1 >= 1) L = n + 1 - sa2[i - 1] + 1; + for (int j = n + 1 - sa2[i], p = stk.size() - 1; j >= L; j--) { + while (p > 0 && stk[p - 1].second >= j) p--; + res[j] = stk[p].first; + } + } + write(res[1]); + for (int i = 2; i <= n; i++) write(' ', res[i]); + write("\n"); + return 0; +} \ No newline at end of file diff --git a/ACMOJ-2133.cpp b/ACMOJ-2133.cpp new file mode 100644 index 0000000..b97b4ee --- /dev/null +++ b/ACMOJ-2133.cpp @@ -0,0 +1,61 @@ +#include +#include +#include +using namespace std; +typedef long long LL; +const int kMod = 19930726; +const int kMaxN = 1e6 + 10; +int n; +LL K; +char s[kMaxN]; +int d1[kMaxN]; +LL cnt[kMaxN]; +LL qpow(int a, int b) { + LL res = 1; + while (b > 0) { + if (b & 1) res = (res * a) % kMod; + b >>= 1; + a = (a * (LL)a) % kMod; + } + return res; +} +int main() { +#ifdef local + freopen("pro.in", "r", stdin); +#endif + scanf("%d%lld", &n, &K); + scanf("%s", s); + for (int i = 0, l = 0, r = -1; i < n; i++) { + int k = (i > r) ? 1 : min(d1[l + r - i], r - i + 1); + while (0 <= i - k && i + k < n && s[i - k] == s[i + k]) { k++; } + d1[i] = k--; + if (i + k > r) { + l = i - k; + r = i + k; + } + } + LL tot = 0; + for (int i = 0; i < n; i++) { + tot += d1[i]; + cnt[d1[i]]++; + } + if (tot < K) { + printf("-1\n"); + return 0; + } + for(int i=n-1;i>=1;i--) cnt[i]+=cnt[i+1]; + LL lft = K, res = 1; + for (int i = n; i >= 1; i--) { + if (cnt[i] > 0) { + if (cnt[i] < lft) { + res = (res * qpow(2 * i - 1, cnt[i])) % kMod; + lft -= cnt[i]; + } else { + res = (res * qpow(2 * i - 1, lft)) % kMod; + break; + } + } + } + printf("%lld\n", res); + return 0; +} \ No newline at end of file diff --git a/ACMOJ-2139.cpp b/ACMOJ-2139.cpp new file mode 100644 index 0000000..868b9ea --- /dev/null +++ b/ACMOJ-2139.cpp @@ -0,0 +1,144 @@ +#include +#include +#include +#include +#include +#include +#include +using namespace std; +typedef long long LL; +typedef long double LDB; +const int kMaxN = 1e5 + 10; +struct state { + int len, link; + unordered_map next; +}; +int n, m; +char str[kMaxN]; +state st[kMaxN * 2]; +int sz, last; +int prefix_node_id[kMaxN]; +int root_of_node[kMaxN * 2]; +struct SegNodeType { + int lc, rc, sum; +}; +SegNodeType seg[kMaxN * 60]; +int seg_node_tot = 0; +list G[kMaxN * 2]; +int max_depth, fast_jump[kMaxN * 2][20]; +void sam_init() { + st[0].len = 0; + st[0].link = -1; + sz++; + last = 0; +} +void sam_extend(char c) { + int cur = sz++; + st[cur].len = st[last].len + 1; + int p = last; + while (p != -1 && !st[p].next.count(c)) { + st[p].next[c] = cur; + p = st[p].link; + } + if (p == -1) { + st[cur].link = 0; + } else { + int q = st[p].next[c]; + if (st[p].len + 1 == st[q].len) { + st[cur].link = q; + } else { + int clone = sz++; + st[clone].len = st[p].len + 1; + st[clone].next = st[q].next; + st[clone].link = st[q].link; + while (p != -1 && st[p].next[c] == q) { + st[p].next[c] = clone; + p = st[p].link; + } + st[q].link = st[cur].link = clone; + } + } + last = cur; +} +void InsertBasicEndPos(int &rt, int L, int R, int pos) { + if (rt == 0) rt = ++seg_node_tot; + seg[rt].sum++; + if (L == R) return; + int M = (L + R) >> 1; + if (pos <= M) + InsertBasicEndPos(seg[rt].lc, L, M, pos); + else + InsertBasicEndPos(seg[rt].rc, M + 1, R, pos); +} +int Query(int rt, int L, int R, int ql, int qr) { + if (ql <= L && R <= qr) return seg[rt].sum; + int M = (L + R) >> 1; + int res = 0; + if (ql <= M) res += Query(seg[rt].lc, L, M, ql, qr); + if (qr >= M + 1) res += Query(seg[rt].rc, M + 1, R, ql, qr); + return res; +} +int MergeSeg(int p, int q, int L, int R) { + if (p == 0 || q == 0) return p + q; + int cur = ++seg_node_tot; + seg[cur].sum = seg[p].sum + seg[q].sum; + if (L < R) { + int M = (L + R) >> 1; + seg[cur].lc = MergeSeg(seg[p].lc, seg[q].lc, L, M); + seg[cur].rc = MergeSeg(seg[p].rc, seg[q].rc, M + 1, R); + } + return cur; +} +void Dfs(int nd) { + for (int p = 1; p <= max_depth; p++) { + if (fast_jump[nd][p - 1] == -1) + fast_jump[nd][p] = -1; + else + fast_jump[nd][p] = fast_jump[fast_jump[nd][p - 1]][p - 1]; + } + for (auto v : G[nd]) { + fast_jump[v][0] = nd; + Dfs(v); + root_of_node[nd] = MergeSeg(root_of_node[nd], root_of_node[v], 1, n); + } +} +bool IsValid(int len, int a, int b, int c, int d) { + int cur = prefix_node_id[c + len - 1]; + for (int p = max_depth; p >= 0; p--) { + if (fast_jump[cur][p] != -1 && st[fast_jump[cur][p]].len >= len) + cur = fast_jump[cur][p]; + } + return Query(root_of_node[cur], 1, n, a + len - 1, b) > 0; +} +int main() { +#ifdef local + freopen("pro.in", "r", stdin); +#endif + scanf("%d%d", &n, &m); + scanf("%s", str + 1); + sam_init(); + for (int i = 1; i <= n; i++) { + sam_extend(str[i]); + prefix_node_id[i] = last; + InsertBasicEndPos(root_of_node[last], 1, n, i); + } + for (int i = 1; i < sz; i++) G[st[i].link].push_back(i); + max_depth = log2(sz + 1) + 1; + memset(fast_jump, -1, sizeof(fast_jump)); + Dfs(0); + while (m-- > 0) { + int a, b, c, d; + scanf("%d%d%d%d", &a, &b, &c, &d); + int L = 0, R = min(b - a + 1, d - c + 1), M, res = 0; + while (L <= R) { + M = (L + R) >> 1; + if (IsValid(M, a, b, c, d)) { + res = M; + L = M + 1; + } else + R = M - 1; + } + printf("%d\n", res); + } + return 0; +} \ No newline at end of file diff --git a/ACMOJ-2140.cpp b/ACMOJ-2140.cpp new file mode 100644 index 0000000..cbeb435 --- /dev/null +++ b/ACMOJ-2140.cpp @@ -0,0 +1,106 @@ +#include +#include +#include +#include +#include +using namespace std; +typedef long long LL; +typedef unsigned long long ULL; +typedef long double LDB; +const int kMaxN = 1e6 + 10; +char S[kMaxN], T[kMaxN]; +struct Block { + enum TypeT { wild, exact } type; + int L, R; +}; +Block S_block[kMaxN], T_block[kMaxN]; +int S_block_cnt, T_block_cnt; +int len_S, len_T; +ULL S_hash_data[kMaxN], T_hash_data[kMaxN], ksm[kMaxN]; +void Process(char *S, int len_S, Block *blocks, int &block_cnt) { + int current_left_bound = 0; + Block::TypeT current_type = + (S[0] == '?' ? Block::TypeT::wild : Block::TypeT::exact); + for (int i = 1; i < len_S; i++) { + Block::TypeT this_type = + (S[i] == '?' ? Block::TypeT::wild : Block::TypeT::exact); + if (this_type == current_type) continue; + blocks[block_cnt++] = Block{current_type, current_left_bound, i - 1}; + current_type = this_type; + current_left_bound = i; + } + blocks[block_cnt++] = Block{current_type, current_left_bound, len_S - 1}; +} +void PrepareHash(char *src, int len, ULL *dst) { + static const ULL mul = 131; + dst[0] = src[0] - 'a' + 1; + for (int i = 1; i < len; i++) { + dst[i] = dst[i - 1] * mul; + dst[i] += src[i] - 'a' + 1; + } +} +ULL GetHsh(char *str, ULL *dat, int L, int R) { + ULL res = 0; + if (L > 0) + res = dat[R] - dat[L - 1] * ksm[R - L + 1]; + else + res = dat[R]; + return res; +} +bool Matched(int pos) { + int current_T_iterator = 0; + static int stored_begin_S_iterator = 0; + int current_S_iterator = stored_begin_S_iterator; + Block current_S_block = S_block[0]; + Block current_T_block = T_block[0]; + while (S_block[current_S_iterator].R < pos) current_S_iterator++; + stored_begin_S_iterator = current_S_iterator; + current_S_block = S_block[current_S_iterator]; + assert(current_S_block.L <= pos); + assert(current_S_block.R >= pos); + current_S_block.L = pos; + while (true) { + int current_compare_length = min(current_S_block.R - current_S_block.L + 1, + current_T_block.R - current_T_block.L + 1); + if (current_S_block.type == Block::TypeT::exact && + current_T_block.type == Block::TypeT::exact) { + if (GetHsh(S, S_hash_data, current_S_block.L, + current_S_block.L + current_compare_length - 1) != + GetHsh(T, T_hash_data, current_T_block.L, + current_T_block.L + current_compare_length - 1)) + return false; + } + if (current_compare_length == current_T_block.R - current_T_block.L + 1) { + if (current_T_iterator == T_block_cnt - 1) return true; + current_T_iterator++; + current_T_block = T_block[current_T_iterator]; + } else + current_T_block.L += current_compare_length; + if (current_compare_length == current_S_block.R - current_S_block.L + 1) { + current_S_iterator++; + current_S_block = S_block[current_S_iterator]; + } else + current_S_block.L += current_compare_length; + } + return true; +} +int main() { +#ifdef local + freopen("pro.in", "r", stdin); +#endif + scanf("%s%s", S, T); + len_S = strlen(S); + len_T = strlen(T); + Process(S, len_S, S_block, S_block_cnt); + Process(T, len_T, T_block, T_block_cnt); + PrepareHash(S, len_S, S_hash_data); + PrepareHash(T, len_T, T_hash_data); + ksm[0] = 1; + static const ULL mul = 131; + for (int i = 1; i < kMaxN; i++) ksm[i] = ksm[i - 1] * mul; + for (int pos = 0; pos < len_S - len_T + 1; pos++) { + if (Matched(pos)) printf("%d\n", pos); + // fprintf(stderr, "pos=%d\n", pos); + } + return 0; +} \ No newline at end of file diff --git a/ACMOJ-2147.cpp b/ACMOJ-2147.cpp new file mode 100644 index 0000000..b8a7212 --- /dev/null +++ b/ACMOJ-2147.cpp @@ -0,0 +1,66 @@ +#include +#include +#include +#include +using namespace std; +typedef long long LL; +typedef long double LDB; +const int kMaxN = 510; +const int kMaxT = 4e6 + 100 + 10; +int n, m; +int t[kMaxN]; +int bucket[kMaxT], bucket_tot[kMaxT], max_t; +LL f[kMaxT], bucket_t_sum[kMaxT]; +int Q[kMaxT], QL, QR; +inline LL GetY(int id) { return f[id] + bucket_t_sum[id]; } +int main() { +#ifdef local + freopen("pro.in", "r", stdin); +#endif + scanf("%d%d", &n, &m); + for (int i = 1; i <= n; i++) { + scanf("%d", &t[i]); + bucket[t[i]]++; + max_t = t[i] > max_t ? t[i] : max_t; + } + bucket_tot[0] = bucket[0]; + for (int i = 1; i <= max_t + m - 1; i++) { + bucket_tot[i] = bucket_tot[i - 1] + bucket[i]; + bucket_t_sum[i] = bucket_t_sum[i - 1] + i * (LL)bucket[i]; + } + QL = 0; + QR = -1; + int pend_cur = 0; + for (int i = 0; i <= max_t + m - 1; i++) { + f[i] = bucket_tot[i] * (LL)i - bucket_t_sum[i]; + // for (int j = 0; j + m <= i; j++) { + // f[i] = min(f[i], f[j] + (bucket_tot[i] - bucket_tot[j]) * (LL)i - + // bucket_t_sum[i] + bucket_t_sum[j]); + // // f[j] + bucket_t_sum[j] =i*bucket_tot[j]+ f[i] - bucket_tot[i]*i + + // // bucket_t_sum[i] + // } + while (pend_cur + m <= i) { + while (QR - QL + 1 >= 2 && + (bucket_tot[pend_cur] - bucket_tot[Q[QR - 1]]) * + (GetY(Q[QR]) - GetY(Q[QR - 1])) - + (GetY(pend_cur) - GetY(Q[QR - 1])) * + (bucket_tot[Q[QR]] - bucket_tot[Q[QR - 1]]) >= + 0) + QR--; + Q[++QR] = pend_cur; + pend_cur++; + } + while (QR - QL + 1 >= 2 && + GetY(Q[QL + 1]) - GetY(Q[QL]) <= + i * (LL)(bucket_tot[Q[QL + 1]] - bucket_tot[Q[QL]])) + QL++; + if (QL <= QR) + f[i] = min(f[i], f[Q[QL]] + (bucket_tot[i] - bucket_tot[Q[QL]]) * (LL)i - + bucket_t_sum[i] + bucket_t_sum[Q[QL]]); + // printf("f(%d)=%lld\n", i, f[i]); + } + LL res = 0x3f3f3f3f3f3f3f3f; + for (int i = max_t; i <= max_t + m - 1; i++) res = min(res, f[i]); + printf("%lld\n", res); + return 0; +} \ No newline at end of file diff --git a/ACMOJ-2148.cpp b/ACMOJ-2148.cpp new file mode 100644 index 0000000..7fc64ac --- /dev/null +++ b/ACMOJ-2148.cpp @@ -0,0 +1,107 @@ +#include +#include +#include +using namespace std; +typedef long long LL; +typedef long double LDB; +const int kMaxN = 1e5 + 10; +int N, S; +LDB A[kMaxN], B[kMaxN], R[kMaxN]; +struct NodeType { + int rawid; + LDB a, b, r, f; +}; +NodeType nodes[kMaxN]; +inline LDB GetX(const NodeType &node) { + return node.f * node.r / (node.a * node.r + node.b); +} +inline LDB GetY(const NodeType &node) { + return node.f / (node.a * node.r + node.b); +} +bool CmpX(const NodeType &na, const NodeType &nb) { + return GetX(na) < GetX(nb); +} +bool CmpId(const NodeType &na, const NodeType &nb) { + return na.rawid < nb.rawid; +} +bool CmpK(const NodeType &na, const NodeType &nb) { + return -na.a / na.b > -nb.a / nb.b; +} +int Q[kMaxN], QL, QR; +typedef bool (*CmpType)(const NodeType &, const NodeType &); +void MergeSort(NodeType *beg, NodeType *end, CmpType cmp) { + if (end - beg <= 1) return; + size_t len = end - beg; + NodeType *mid = beg + (len >> 1); + MergeSort(beg, mid, cmp); + MergeSort(mid, end, cmp); + NodeType *tmp = new NodeType[len]; + NodeType *cur_tmp = tmp, *cur_L = beg, *cur_R = mid; + while ((cur_L < mid) && (cur_R < end)) { + if (cmp(*cur_L, *cur_R)) + *(cur_tmp++) = *(cur_L++); + else + *(cur_tmp++) = *(cur_R++); + } + while (cur_L < mid) *(cur_tmp++) = *(cur_L++); + while (cur_R < end) *(cur_tmp++) = *(cur_R++); + cur_tmp = tmp; + NodeType *cur_dst = beg; + while (cur_dst < end) *(cur_dst++) = *(cur_tmp++); + delete[] tmp; +} +void CDQ(int L, int R) { + if (L == R) return; + int M = (L + R) >> 1; + CDQ(L, M); + MergeSort(nodes + L, nodes + M + 1, CmpX); + MergeSort(nodes + M + 1, nodes + R + 1, CmpK); + Q[QL = QR = 0] = L; + for (int i = L + 1; i <= M; i++) { + while (QR - QL + 1 >= 2 && + (GetX(nodes[Q[QR]]) - GetX(nodes[Q[QR - 1]])) * + (GetY(nodes[i]) - GetY(nodes[Q[QR - 1]])) - + (GetY(nodes[Q[QR]]) - GetY(nodes[Q[QR - 1]])) * + (GetX(nodes[i]) - GetX(nodes[Q[QR - 1]])) >= + 0) + QR--; + Q[++QR] = i; + } + LDB base = 0; + for (int i = L; i <= M; i++) base = max(base, nodes[i].f); + for (int i = M + 1; i <= R; i++) { + while (QR - QL + 1 >= 2 && + (GetY(nodes[Q[QL + 1]]) - GetY(nodes[Q[QL]])) / + (GetX(nodes[Q[QL + 1]]) - GetX(nodes[Q[QL]])) >= + -nodes[i].a / nodes[i].b) + QL++; + nodes[i].f = max(nodes[i].f, base); + nodes[i].f = max(nodes[i].f, nodes[i].a * GetX(nodes[Q[QL]]) + + nodes[i].b * GetY(nodes[Q[QL]])); + } + MergeSort(nodes + M + 1, nodes + R + 1, CmpId); + CDQ(M + 1, R); +} +int main() { +#ifdef local + freopen("pro.in", "r", stdin); +#endif + scanf("%d%d", &N, &S); + for (int i = 1; i <= N; i++) { + scanf("%Lf%Lf%Lf", &A[i], &B[i], &R[i]); + nodes[i].rawid = i; + nodes[i].a = A[i]; + nodes[i].b = B[i]; + nodes[i].r = R[i]; + } + nodes[1].f = S; + CDQ(1, N); + // for (int i = 1; i <= N; i++) + // printf("f(%d)=%.3Lf\n", nodes[i].rawid, nodes[i].f); + for (int i = 1; i <= N; i++) + if (nodes[i].rawid == N) { + printf("%.3Lf\n", nodes[i].f); + return 0; + } + return 0; +} \ No newline at end of file diff --git a/ACMOJ-2163.cpp b/ACMOJ-2163.cpp new file mode 100644 index 0000000..18e0fba --- /dev/null +++ b/ACMOJ-2163.cpp @@ -0,0 +1,36 @@ +#include +#include +#include +#include +using namespace std; +typedef long long LL; +typedef long double LDB; +const int kMaxN = 1e5 + 10; +int n, key[kMaxN], w[kMaxN]; +int stk[kMaxN], ls[kMaxN], rs[kMaxN]; +void dfs(int rt) { + printf("%d ", rt); + if (ls[rt]) dfs(ls[rt]); + if (rs[rt]) dfs(rs[rt]); +} +int main() { +#ifdef local + freopen("pro.in", "r", stdin); +#endif + scanf("%d", &n); + for (int i = 1; i <= n; i++) { + scanf("%d", &key[i]); + w[key[i]] = i; + } + int top = 0; + for (int i = 1; i <= n; i++) { + int k = top; + while (k > 0 && w[stk[k]] > w[i]) k--; + if (k) rs[stk[k]] = i; // rs代表笛卡尔树每个节点的右儿子 + if (k < top) ls[i] = stk[k + 1]; // ls代表笛卡尔树每个节点的左儿子 + stk[++k] = i; + top = k; + } + dfs(stk[1]); + return 0; +} \ No newline at end of file diff --git a/ACMOJ-2165.cpp b/ACMOJ-2165.cpp new file mode 100644 index 0000000..ed39984 --- /dev/null +++ b/ACMOJ-2165.cpp @@ -0,0 +1,59 @@ +#include +#include +#include +#include +using namespace std; +typedef long long LL; +typedef long double LDB; +const int kMaxN = 1e4 + 10; +const LDB kEps = 1e-4; +int n, a, b; +LDB p[kMaxN], q[kMaxN]; +LDB calcxy(LDB x, LDB y) { + LDB tot = a * x + b * y; + for (int i = 1; i <= n; i++) + tot += max({LDB(0), p[i] - x, q[i] - y, p[i] + q[i] - p[i] * q[i] - x - y}); + return tot; +} +LDB calcx(LDB x) { + LDB res=0; + LDB left_bound = -1e4, right_bound = 1e4; + while (right_bound - left_bound > kEps) { + LDB l_mid = (left_bound + left_bound + right_bound) / 3; + LDB r_mid = (left_bound + right_bound + right_bound) / 3; + LDB l_res = calcxy(x, l_mid); + LDB r_res = calcxy(x, r_mid); + res = (l_res + r_res) / 2; + if (l_res > r_res) + left_bound = l_mid; + else + right_bound = r_mid; + } + return res; +} +LDB calc() { + LDB res = 0; + LDB left_bound = -1e4, right_bound = 1e4; + while (right_bound - left_bound > kEps) { + LDB l_mid = (left_bound + left_bound + right_bound) / 3; + LDB r_mid = (left_bound + right_bound + right_bound) / 3; + LDB l_res = calcx(l_mid); + LDB r_res = calcx(r_mid); + res = (l_res + r_res) / 2; + if (l_res > r_res) + left_bound = l_mid; + else + right_bound = r_mid; + } + return res; +} +int main() { +#ifdef local + freopen("pro.in", "r", stdin); +#endif + scanf("%d%d%d", &n, &a, &b); + for (int i = 1; i <= n; i++) scanf("%Lf", &p[i]); + for (int i = 1; i <= n; i++) scanf("%Lf", &q[i]); + printf("%.2Lf\n", calc()); + return 0; +} \ No newline at end of file diff --git a/ACMOJ-2178.cpp b/ACMOJ-2178.cpp new file mode 100644 index 0000000..8e5353c --- /dev/null +++ b/ACMOJ-2178.cpp @@ -0,0 +1,92 @@ +#include +#include +#include +#include +#include +using namespace std; +typedef long long LL; +typedef long double LDB; +const int kMaxN = 310; +char s[kMaxN]; +int N, M; +int Calc1(int st) { + int target[20] = {0}; + for (int i = 0; i < M; i++) target[i] = (st >> i) & 1; + int cost[kMaxN][2] = {0}; + int bucket_tot = N / M; + int left = N % M; + int initial_cost = 0; + for (int i = 0; i < left; i++) + initial_cost += s[bucket_tot * M + i] != target[i] ? 1 : 0; + for (int i = 0; i < bucket_tot; i++) { + for (int j = 0; j < M; j++) { + if (s[i * M + j] == target[j]) + cost[i][1]++; + else + cost[i][0]++; + } + } + int dp[kMaxN][2]; + memset(dp, 0x3f, sizeof(dp)); + dp[bucket_tot][0] = initial_cost; + for (int i = bucket_tot - 1; i >= 0; i--) { + dp[i][0] = min(dp[i + 1][0] + cost[i][0], dp[i + 1][1] + cost[i][0] + 1); + dp[i][1] = min(dp[i + 1][0] + cost[i][1] + 1, dp[i + 1][1] + cost[i][1]); + } + return min(dp[0][0], dp[0][1]); +} +void Case1() { + int res = 0x3f3f3f3f; + for (int i = 0; i < N; i++) s[i] = s[i] - '0'; + for (int st = 0; st < (1 << M); st++) res = min(res, Calc1(st)); + printf("%d\n", res); +} +int Calc2(int st) { + int bucket_tot = N / M; + int cur_status = 0, status = 0; + int tot = 0; + for (int i = bucket_tot - 1; i >= 0; i--) { + int cur = (st >> i) & 1; + tot += cur; + cur_status ^= cur; + status <<= 1; + status |= cur_status; + } + int S[kMaxN]; + for (int i = 0; i < N; i++) { + S[i] = s[i] - '0'; + int block_id = i / M; + int hat = (status >> block_id) & 1; + S[i] ^= hat; + } + for (int i = 0; i < M; i++) { + int cnt_one = 0; + int cnt_zero = 0; + for (int j = i; j < N; j += M) { + if (S[j] == 1) + cnt_one++; + else + cnt_zero++; + } + tot += min(cnt_one, cnt_zero); + } + return tot; +} +void Case2() { + int bucket_tot = N / M; + int res = 0x3f3f3f3f; + for (int st = 0; st < (1 << bucket_tot); st++) res = min(res, Calc2(st)); + printf("%d\n", res); +} +int main() { +#ifdef local + freopen("pro.in", "r", stdin); +#endif + scanf("%s%d", s, &M); + N = strlen(s); + if (M <= sqrt(N)) + Case1(); + else + Case2(); + return 0; +} \ No newline at end of file diff --git a/ACMOJ-2179.cpp b/ACMOJ-2179.cpp new file mode 100644 index 0000000..c999bee --- /dev/null +++ b/ACMOJ-2179.cpp @@ -0,0 +1,78 @@ +#include +#include +#include +using namespace std; +template +inline void read(T &t) { + t = 0; + int ch, f = false; + while (ch = getchar(), !((ch >= '0' && ch <= '9') || ch == '-')) + ; + if (ch == '-') f = true, ch = getchar(); + t = ch ^ 48; + while (ch = getchar(), ch >= '0' && ch <= '9') t = t * 10 + (ch ^ 48); + if (f) t = -t; +} +template +inline void read(T &t, Args &...args) { + read(t); + read(args...); +} +const int maxn = 500005; +const int maxm = 200005; +struct Query { + int l, r, id; +}; +Query q[maxm]; +int n, m, cnt[1000001], tot, a[maxn], res[maxm], bid[maxn]; +inline bool cmp(const Query &a, const Query &b) { + return bid[a.l] != bid[b.l] ? bid[a.l] < bid[b.l] + : ((bid[a.l] & 1) ? a.r < b.r : a.r > b.r); +} +template +void MergeSort(T *beg, T *end, bool (*cmp)(const T &, const T &)) { + if (end - beg <= 1) return; + size_t len = end - beg; + T *mid = beg + (len >> 1); + MergeSort(beg, mid, cmp); + MergeSort(mid, end, cmp); + T *tmp = new T[len]; + T *cur_tmp = tmp, *cur_L = beg, *cur_R = mid; + while ((cur_L < mid) && (cur_R < end)) { + if (cmp(*cur_L, *cur_R)) + *(cur_tmp++) = *(cur_L++); + else + *(cur_tmp++) = *(cur_R++); + } + while (cur_L < mid) *(cur_tmp++) = *(cur_L++); + while (cur_R < end) *(cur_tmp++) = *(cur_R++); + cur_tmp = tmp; + T *cur_dst = beg; + while (cur_dst < end) *(cur_dst++) = *(cur_tmp++); + delete[] tmp; +} +int main() { +#ifdef local + freopen("pro.in", "r", stdin); +#endif + read(n); + for (int i = 1; i <= n; i++) read(a[i]); + read(m); + for (int i = 1; i <= m; i++) read(q[i].l, q[i].r), q[i].id = i; + int blo = sqrt(n); + for (int i = 1; i <= n; i++) bid[i] = (i - 1) / blo + 1; + MergeSort(q + 1, q + 1 + m, cmp); + int l = q[1].l, r = q[1].r; + for (int i = l; i <= r; i++) tot += (++cnt[a[i]] == 1); + res[q[1].id] = tot; + for (int i = 2; i <= m; i++) { + Query &Q = q[i]; + while (l < Q.l) tot -= (--cnt[a[l++]] == 0); + while (l > Q.l) tot += (++cnt[a[--l]] == 1); + while (r > Q.r) tot -= (--cnt[a[r--]] == 0); + while (r < Q.r) tot += (++cnt[a[++r]] == 1); + res[Q.id] = tot; + } + for (int i = 1; i <= m; i++) printf("%d\n", res[i]); + return 0; +} \ No newline at end of file diff --git a/ACMOJ-2180.cpp b/ACMOJ-2180.cpp new file mode 100644 index 0000000..acdf5d3 --- /dev/null +++ b/ACMOJ-2180.cpp @@ -0,0 +1,41 @@ +#include +#include +#include +#include +#include +#include +using namespace std; +typedef long long LL; +typedef long double LDB; +const int kMaxN = 1e5 + 10; +int n, m, a[kMaxN]; +LL small_bucket[400][400]; +int main() { +#ifdef local + freopen("pro.in", "r", stdin); +#endif + scanf("%d%d", &n, &m); + for (int i = 1; i <= n; i++) { scanf("%d", &a[i]); } + int boundary = sqrt(n); + assert(boundary < 400); + for (int i = 1; i <= n; i++) + for (int j = 1; j <= boundary; j++) small_bucket[j][i % j] += a[i]; + while (m-- > 0) { + int opt, x, y; + scanf("%d%d%d", &opt, &x, &y); + if (opt == 1) { + if (x <= boundary) { + printf("%lld\n", small_bucket[x][y % x]); + } else { + LL res = 0; + for (int i = y; i <= n; i += x) res += a[i]; + printf("%lld\n", res); + } + } else { + for (int i = 1; i <= boundary; i++) small_bucket[i][x % i] -= a[x]; + a[x] = y; + for (int i = 1; i <= boundary; i++) small_bucket[i][x % i] += a[x]; + } + } + return 0; +} \ No newline at end of file diff --git a/ACMOJ-2181.cpp b/ACMOJ-2181.cpp new file mode 100644 index 0000000..4752bd1 --- /dev/null +++ b/ACMOJ-2181.cpp @@ -0,0 +1,1039 @@ +#ifndef SJTU_EXCEPTIONS_HPP +#define SJTU_EXCEPTIONS_HPP + +#include +#include +#include + +namespace sjtu { + +class exception { + protected: + const std::string variant = ""; + std::string detail = ""; + + public: + exception() {} + exception(const exception &ec) : variant(ec.variant), detail(ec.detail) {} + virtual std::string what() { return variant + " " + detail; } +}; + +class index_out_of_bound : public exception { + /* __________________________ */ +}; + +class runtime_error : public exception { + /* __________________________ */ +}; + +class invalid_iterator : public exception { + /* __________________________ */ +}; + +class container_is_empty : public exception { + /* __________________________ */ +}; +} // namespace sjtu + +#endif +#ifndef SJTU_UTILITY_HPP +#define SJTU_UTILITY_HPP + +#include + +namespace sjtu { + +template +class pair { + public: + T1 first; + T2 second; + constexpr pair() : first(), second() {} + pair(const pair &other) = default; + pair(pair &&other) = default; + pair(const T1 &x, const T2 &y) : first(x), second(y) {} + template + pair(U1 &&x, U2 &&y) : first(x), second(y) {} + template + pair(const pair &other) : first(other.first), second(other.second) {} + template + pair(pair &&other) : first(other.first), second(other.second) {} +}; + +} // namespace sjtu + +#endif +/** + * implement a container like std::map + */ +#ifndef SJTU_MAP_HPP +#define SJTU_MAP_HPP + +// only for std::less +#include +#include +#include +#include +#ifndef NDEBUG +#include // only for debug use +#include // only for debug use +#endif + +namespace sjtu { +struct map_iterator_tag : std::bidirectional_iterator_tag {}; +template > +class map { + public: + /** + * the internal type of data. + * it should have a default constructor, a copy constructor. + * You can use sjtu::map as value_type by typedef. + */ + typedef pair value_type; + + private: + static Compare comparer; + /** + * The NIL Node is recorded as a nullptr pointer. + */ + struct RedBlackTreeNodeType { + value_type val; + RedBlackTreeNodeType *left, *right, *parent; + enum RedBlackTreeColorType { RED, BLACK } color; + RedBlackTreeNodeType() + : left(nullptr), right(nullptr), parent(nullptr), color(RED) {} + RedBlackTreeNodeType(const value_type &val, RedBlackTreeNodeType *left, + RedBlackTreeNodeType *right, + RedBlackTreeNodeType *parent, + RedBlackTreeColorType color) + : val(val), left(left), right(right), parent(parent), color(color) {} + inline RedBlackTreeNodeType *GetGrandParent() const noexcept { + if (parent == nullptr) +#if __cplusplus >= 202002L + [[unlikely]] +#endif + return nullptr; + return parent->parent; + } + inline RedBlackTreeNodeType *GetUncle() const noexcept { + RedBlackTreeNodeType *grand_parent = GetGrandParent(); + if (grand_parent == nullptr) +#if __cplusplus >= 202002L + [[unlikely]] +#endif + return nullptr; + if (parent == grand_parent->left) + return grand_parent->right; + else + return grand_parent->left; + } + inline RedBlackTreeNodeType *GetSibling() const noexcept { + if (parent == nullptr) +#if __cplusplus >= 202002L + [[unlikely]] +#endif + return nullptr; + if (this == parent->left) + return parent->right; + else + return parent->left; + } + inline RedBlackTreeNodeType *&GetSelfPath( + RedBlackTreeNodeType *&tree_root) noexcept { + if (parent == nullptr) return tree_root; + if (this == parent->left) + return parent->left; + else + return parent->right; + } + inline void SetChildrensParent() noexcept { + if (left != nullptr) left->parent = this; + if (right != nullptr) right->parent = this; + } + inline void RotateLeft(RedBlackTreeNodeType *&tree_root) noexcept { + assert(this->right != nullptr); + RedBlackTreeNodeType *parent_backup = parent; + RedBlackTreeNodeType *&path = this->GetSelfPath(tree_root); + RedBlackTreeNodeType *replacement = this->right; + this->right = replacement->left; + replacement->left = this; + this->SetChildrensParent(); + replacement->SetChildrensParent(); + path = replacement; + replacement->parent = parent_backup; + } + inline void RotateRight(RedBlackTreeNodeType *&tree_root) noexcept { + assert(this->left != nullptr); + RedBlackTreeNodeType *parent_backup = parent; + RedBlackTreeNodeType *&path = this->GetSelfPath(tree_root); + RedBlackTreeNodeType *replacement = this->left; + this->left = replacement->right; + replacement->right = this; + this->SetChildrensParent(); + replacement->SetChildrensParent(); + path = replacement; + replacement->parent = parent_backup; + } + void InsertFixUp(RedBlackTreeNodeType *&tree_root) { + if (parent == nullptr) { + // Case 1 + color = RedBlackTreeColorType::BLACK; + return; + } + if (parent->color == RedBlackTreeColorType::BLACK) return; + if (parent->parent == nullptr) { + // Case 2 & 3 + parent->color = RedBlackTreeColorType::BLACK; + return; + } + RedBlackTreeNodeType *uncle = GetUncle(); + RedBlackTreeNodeType *grand_parent = GetGrandParent(); + if (uncle != nullptr && uncle->color == RedBlackTreeColorType::RED) { + // Case 4 + parent->color = RedBlackTreeColorType::BLACK; + uncle->color = RedBlackTreeColorType::BLACK; + grand_parent->color = RedBlackTreeColorType::RED; + grand_parent->InsertFixUp(tree_root); + return; + } + if (grand_parent->left == parent) { + if (parent->right == this) { + RedBlackTreeNodeType *old_parent = parent; + parent->RotateLeft(tree_root); + assert(old_parent->parent == this); + old_parent->InsertFixUp(tree_root); + return; + } + grand_parent->RotateRight(tree_root); + assert(grand_parent->parent == parent); + parent->color = RedBlackTreeColorType::BLACK; + grand_parent->color = RedBlackTreeColorType::RED; + } else { + if (parent->left == this) { + RedBlackTreeNodeType *old_parent = parent; + parent->RotateRight(tree_root); + assert(old_parent->parent == this); + old_parent->InsertFixUp(tree_root); + return; + } + grand_parent->RotateLeft(tree_root); + assert(grand_parent->parent == parent); + parent->color = RedBlackTreeColorType::BLACK; + grand_parent->color = RedBlackTreeColorType::RED; + } + } + /** + * @brief Insert a new node into the tree. + * + * @details This function will insert a new node into the tree. If insert + * successfully, it will return true. + * + * @param tree_root The root of the tree. + * @param val The value to be inserted. + * @param allow_replacement Whether to allow replacement if the key already + * exists. + * + * @return Whether the insertion is successful and where the insertion is. + * + * @note Note that tree_root is a reference to the root of the tree. This + * function will modify the tree_root if necessary. + */ + std::pair Insert( + RedBlackTreeNodeType *&tree_root, const value_type &val, + bool allow_replacement) { + if (comparer(val.first, this->val.first)) { + if (left == nullptr) { + left = new RedBlackTreeNodeType(val, nullptr, nullptr, this, + RedBlackTreeColorType::RED); + left->parent = this; + RedBlackTreeNodeType *addr = left; + left->InsertFixUp(tree_root); + return std::pair(addr, true); + } else { + return left->Insert(tree_root, val, allow_replacement); + } + } else if (comparer(this->val.first, val.first)) { + if (right == nullptr) { + right = new RedBlackTreeNodeType(val, nullptr, nullptr, this, + RedBlackTreeColorType::RED); + right->parent = this; + RedBlackTreeNodeType *addr = right; + right->InsertFixUp(tree_root); + return std::pair(addr, true); + } else { + return right->Insert(tree_root, val, allow_replacement); + } + } else { + if (allow_replacement) { + this->val.second = val.second; + return std::pair(this, false); + } + } + return std::pair(this, false); + } + /** + * @brief The definition of ReleaseAll. + * + * @details This fuction will be called when the whole map is destructed. It + * will release all the memory allocated. + * + * @note Note that the node itself must be released outside this function. + */ + void ReleaseAll() { + if (left) left->ReleaseAll(); + if (right) right->ReleaseAll(); + delete left; + delete right; + } + RedBlackTreeNodeType *Find(const decltype(val.first) &key) { + if (comparer(key, val.first)) { + if (left == nullptr) return nullptr; + return left->Find(key); + } else if (comparer(val.first, key)) { + if (right == nullptr) return nullptr; + return right->Find(key); + } else { + return this; + } + } + /** + * @brief Swap the node with its successor. + * + * @details This function will swap the node with its successor. + * + * @note The color is not swapped. + */ + inline static void SwapNodeWithItsSuccessor( + RedBlackTreeNodeType *node, RedBlackTreeNodeType *successor, + RedBlackTreeNodeType *&tree_root) { + RedBlackTreeNodeType *left_of_node = node->left; + RedBlackTreeNodeType *right_of_node = node->right; + RedBlackTreeNodeType *parent_of_node = node->parent; + RedBlackTreeColorType color_of_node = node->color; + RedBlackTreeNodeType *&path_of_node = node->GetSelfPath(tree_root); + RedBlackTreeNodeType *left_of_successor = successor->left; + RedBlackTreeNodeType *right_of_successor = successor->right; + RedBlackTreeNodeType *parent_of_successor = successor->parent; + RedBlackTreeColorType color_of_successor = successor->color; + RedBlackTreeNodeType *&path_of_successor = + successor->GetSelfPath(tree_root); + node->color = color_of_successor; + successor->color = color_of_node; + if (parent_of_successor == node) { + successor->left = left_of_node; + successor->right = node; + successor->SetChildrensParent(); + successor->parent = parent_of_node; + path_of_node = successor; + node->left = left_of_successor; + node->right = right_of_successor; + node->SetChildrensParent(); + } else { + successor->left = left_of_node; + successor->right = right_of_node; + successor->SetChildrensParent(); + successor->parent = parent_of_node; + path_of_node = successor; + node->left = left_of_successor; + node->right = right_of_successor; + node->SetChildrensParent(); + node->parent = parent_of_successor; + path_of_successor = node; + } + } + void DeleteFixUp(RedBlackTreeNodeType *&tree_root) { + assert(this->color == RedBlackTreeColorType::BLACK); + if (this == tree_root) return; + RedBlackTreeNodeType *sibling = GetSibling(); + assert(sibling != nullptr); + if (sibling->color == RedBlackTreeColorType::RED) { + // Case 1 + parent->color = RedBlackTreeColorType::RED; + sibling->color = RedBlackTreeColorType::BLACK; + if (this == parent->left) { + parent->RotateLeft(tree_root); + } else { + parent->RotateRight(tree_root); + } + this->DeleteFixUp(tree_root); + return; + } + RedBlackTreeNodeType *close_nephew = nullptr; + RedBlackTreeNodeType *distant_nephew = nullptr; + if (this == parent->left) { + close_nephew = sibling->left; + distant_nephew = sibling->right; + } else { + close_nephew = sibling->right; + distant_nephew = sibling->left; + } + if (sibling->color == RedBlackTreeColorType::BLACK && + this->parent->color == RedBlackTreeColorType::RED && + (close_nephew == nullptr || + close_nephew != nullptr && + close_nephew->color == RedBlackTreeColorType::BLACK) && + (distant_nephew == nullptr || + distant_nephew != nullptr && + distant_nephew->color == RedBlackTreeColorType::BLACK)) { + // Case 2 + sibling->color = RedBlackTreeColorType::RED; + this->parent->color = RedBlackTreeColorType::BLACK; + return; + } + if (sibling->color == RedBlackTreeColorType::BLACK && + this->parent->color == RedBlackTreeColorType::BLACK && + (close_nephew == nullptr || + close_nephew != nullptr && + close_nephew->color == RedBlackTreeColorType::BLACK) && + (distant_nephew == nullptr || + distant_nephew != nullptr && + distant_nephew->color == RedBlackTreeColorType::BLACK)) { + // Case 3 + sibling->color = RedBlackTreeColorType::RED; + this->parent->DeleteFixUp(tree_root); + return; + } + if (close_nephew != nullptr && + close_nephew->color == RedBlackTreeColorType::RED) { + // Case 4 + if (this == parent->left) { + sibling->color = RedBlackTreeColorType::RED; + close_nephew->color = RedBlackTreeColorType::BLACK; + sibling->RotateRight(tree_root); + } else { + sibling->color = RedBlackTreeColorType::RED; + close_nephew->color = RedBlackTreeColorType::BLACK; + sibling->RotateLeft(tree_root); + } + this->DeleteFixUp(tree_root); + return; + } + assert(distant_nephew != nullptr && + distant_nephew->color == RedBlackTreeColorType::RED); + // Then it must be Case 5 + if (this == parent->left) { + std::swap(sibling->color, parent->color); + distant_nephew->color = RedBlackTreeColorType::BLACK; + parent->RotateLeft(tree_root); + } else { + std::swap(sibling->color, parent->color); + distant_nephew->color = RedBlackTreeColorType::BLACK; + parent->RotateRight(tree_root); + } + } + static void DeleteNode(RedBlackTreeNodeType *pos, + RedBlackTreeNodeType *&tree_root) { + if (pos->parent == nullptr && pos->left == nullptr && + pos->right == nullptr) { + // Case 0: The only node in the tree. + delete pos; + tree_root = nullptr; + return; + } + if (pos->left != nullptr && pos->right != nullptr) { + // Case 1: The node has two children. Then we swap the node with its + // successor and just delete the successor. + RedBlackTreeNodeType *successor = pos->right; + while (successor->left != nullptr) successor = successor->left; + SwapNodeWithItsSuccessor(pos, successor, tree_root); + DeleteNode(pos, tree_root); + return; + } + if (pos->left == nullptr && pos->right == nullptr) { + // Case 2 + if (pos->color == RedBlackTreeColorType::BLACK) { + pos->DeleteFixUp(tree_root); + } + pos->GetSelfPath(tree_root) = nullptr; + delete pos; + return; + } + // Case 3 + RedBlackTreeNodeType *replacement = + (pos->left != nullptr ? pos->left : pos->right); + assert(replacement != nullptr); + assert(replacement->color == RedBlackTreeColorType::RED); + pos->GetSelfPath(tree_root) = replacement; + replacement->parent = pos->parent; + replacement->color = RedBlackTreeColorType::BLACK; + delete pos; + } + static void CopyFrom(RedBlackTreeNodeType *&target, + const RedBlackTreeNodeType *source) { + if (source == nullptr) return; + target = new RedBlackTreeNodeType(source->val, nullptr, nullptr, nullptr, + source->color); + CopyFrom(target->left, source->left); + CopyFrom(target->right, source->right); + target->SetChildrensParent(); + } + }; + size_t node_count; + RedBlackTreeNodeType *tree_root; + + public: + /** + * see BidirectionalIterator at CppReference for help. + * + * if there is anything wrong throw invalid_iterator. + * like it = map.begin(); --it; + * or it = map.end(); ++end(); + */ + class const_iterator; + class iterator; + friend iterator; + friend const_iterator; + class iterator { + private: + RedBlackTreeNodeType + *raw_pointer; // when iterator points to end(), raw_pointer=nullptr + map *domain; + + public: + // Add some type traits + typedef sjtu::map_iterator_tag iterator_category; + typedef pair value_type; + typedef std::ptrdiff_t difference_type; + typedef value_type *pointer; + typedef value_type &reference; + + friend const_iterator; + friend map; + iterator() : raw_pointer(nullptr), domain(nullptr) {} + iterator(const iterator &other) + : raw_pointer(other.raw_pointer), domain(other.domain) {} + iterator(RedBlackTreeNodeType *raw_pointer, map *domain) + : raw_pointer(raw_pointer), domain(domain) {} + iterator &operator++() { + if (raw_pointer == nullptr) throw invalid_iterator(); + if (raw_pointer->right != nullptr) { + raw_pointer = raw_pointer->right; + while (raw_pointer->left != nullptr) raw_pointer = raw_pointer->left; + } else { + RedBlackTreeNodeType *backup = raw_pointer; + while (raw_pointer->parent != nullptr && + raw_pointer->parent->right == raw_pointer) + raw_pointer = raw_pointer->parent; + if (raw_pointer->parent == nullptr) { + raw_pointer = nullptr; + return *this; + } + raw_pointer = raw_pointer->parent; + } + return *this; + } + iterator operator++(int) { + iterator tmp = *this; + ++*this; + return tmp; + } + iterator &operator--() { + if (raw_pointer == nullptr) { + if (domain == nullptr) throw invalid_iterator(); + if (domain->tree_root == nullptr) throw invalid_iterator(); + raw_pointer = domain->tree_root; + while (raw_pointer->right != nullptr) raw_pointer = raw_pointer->right; + return *this; + } + if (raw_pointer->left != nullptr) { + raw_pointer = raw_pointer->left; + while (raw_pointer->right != nullptr) raw_pointer = raw_pointer->right; + } else { + RedBlackTreeNodeType *backup = raw_pointer; + while (raw_pointer->parent != nullptr && + raw_pointer->parent->left == raw_pointer) + raw_pointer = raw_pointer->parent; + if (raw_pointer->parent == nullptr) { + throw invalid_iterator(); + raw_pointer = nullptr; + return *this; + } + raw_pointer = raw_pointer->parent; + } + return *this; + } + iterator operator--(int) { + iterator tmp = *this; + --*this; + return tmp; + } + /** + * a operator to check whether two iterators are same (pointing to the same + * memory). + */ + value_type &operator*() const { + if (raw_pointer == nullptr) throw invalid_iterator(); + return raw_pointer->val; + } + bool operator==(const iterator &rhs) const { + return domain == rhs.domain && raw_pointer == rhs.raw_pointer; + } + bool operator==(const const_iterator &rhs) const { + return domain == rhs.domain && raw_pointer == rhs.raw_pointer; + } + /** + * some other operator for iterator. + */ + bool operator!=(const iterator &rhs) const { + return domain != rhs.domain || raw_pointer != rhs.raw_pointer; + } + bool operator!=(const const_iterator &rhs) const { + return domain != rhs.domain || raw_pointer != rhs.raw_pointer; + } + + /** + * for the support of it->first. + * See + * + * for help. + */ + value_type *operator->() const noexcept { return &raw_pointer->val; } + }; + class const_iterator { + private: + RedBlackTreeNodeType + *raw_pointer; // when iterator points to end(), raw_pointer=nullptr + const map *domain; + + public: + // Add some type traits + typedef sjtu::map_iterator_tag iterator_category; + typedef pair value_type; + typedef std::ptrdiff_t difference_type; + typedef value_type *pointer; + typedef value_type &reference; + + friend iterator; + friend map; + const_iterator() : raw_pointer(nullptr), domain(nullptr) {} + const_iterator(const const_iterator &other) + : raw_pointer(other.raw_pointer), domain(other.domain) {} + const_iterator(const iterator &other) + : raw_pointer(other.raw_pointer), domain(other.domain) {} + const_iterator(RedBlackTreeNodeType *raw_pointer, const map *domain) + : raw_pointer(raw_pointer), domain(domain) {} + const_iterator &operator++() { + if (raw_pointer == nullptr) throw invalid_iterator(); + if (raw_pointer->right != nullptr) { + raw_pointer = raw_pointer->right; + while (raw_pointer->left != nullptr) raw_pointer = raw_pointer->left; + } else { + RedBlackTreeNodeType *backup = raw_pointer; + while (raw_pointer->parent != nullptr && + raw_pointer->parent->right == raw_pointer) + raw_pointer = raw_pointer->parent; + if (raw_pointer->parent == nullptr) { + raw_pointer = nullptr; + return *this; + } + raw_pointer = raw_pointer->parent; + } + return *this; + } + const_iterator operator++(int) { + const_iterator tmp = *this; + ++*this; + return tmp; + } + const_iterator &operator--() { + if (raw_pointer == nullptr) { + if (domain == nullptr) throw invalid_iterator(); + if (domain->tree_root == nullptr) throw invalid_iterator(); + raw_pointer = domain->tree_root; + while (raw_pointer->right != nullptr) raw_pointer = raw_pointer->right; + return *this; + } + if (raw_pointer->left != nullptr) { + raw_pointer = raw_pointer->left; + while (raw_pointer->right != nullptr) raw_pointer = raw_pointer->right; + } else { + RedBlackTreeNodeType *backup = raw_pointer; + while (raw_pointer->parent != nullptr && + raw_pointer->parent->left == raw_pointer) + raw_pointer = raw_pointer->parent; + if (raw_pointer->parent == nullptr) { + throw invalid_iterator(); + raw_pointer = nullptr; + return *this; + } + raw_pointer = raw_pointer->parent; + } + return *this; + } + const_iterator operator--(int) { + const_iterator tmp = *this; + --*this; + return tmp; + } + /** + * a operator to check whether two iterators are same (pointing to the same + * memory). + */ + const value_type &operator*() const { + if (raw_pointer == nullptr) throw invalid_iterator(); + return raw_pointer->val; + } + bool operator==(const iterator &rhs) const { + return domain == rhs.domain && raw_pointer == rhs.raw_pointer; + } + bool operator==(const const_iterator &rhs) const { + return domain == rhs.domain && raw_pointer == rhs.raw_pointer; + } + /** + * some other operator for iterator. + */ + bool operator!=(const iterator &rhs) const { + return domain != rhs.domain || raw_pointer != rhs.raw_pointer; + } + bool operator!=(const const_iterator &rhs) const { + return domain != rhs.domain || raw_pointer != rhs.raw_pointer; + } + value_type *operator->() const noexcept { return &raw_pointer->val; } + }; + map() : node_count(0), tree_root(nullptr) {} + map(const map &other) { + node_count = other.node_count; + tree_root = nullptr; + RedBlackTreeNodeType::CopyFrom(tree_root, other.tree_root); + } + map(map &&other) { + node_count = other.node_count; + tree_root = other.tree_root; + other.node_count = 0; + other.tree_root = nullptr; + } + /** + * assignment operator + */ + map &operator=(const map &other) { + if (this == &other) return *this; + if (tree_root) tree_root->ReleaseAll(); + delete tree_root; + node_count = other.node_count; + RedBlackTreeNodeType::CopyFrom(tree_root, other.tree_root); + return *this; + } + map &operator=(map &&other) { + if (this == &other) return *this; + if (tree_root) tree_root->ReleaseAll(); + delete tree_root; + node_count = other.node_count; + tree_root = other.tree_root; + other.node_count = 0; + other.tree_root = nullptr; + return *this; + } + ~map() { + if (tree_root) tree_root->ReleaseAll(); + delete tree_root; + } + /** + * access specified element with bounds checking + * Returns a reference to the mapped value of the element with key equivalent + * to key. If no such element exists, an exception of type + * `index_out_of_bound' + */ + T &at(const Key &key) { + if (tree_root == nullptr) throw index_out_of_bound(); + RedBlackTreeNodeType *result = tree_root->Find(key); + if (result == nullptr) throw index_out_of_bound(); + return result->val.second; + } + const T &at(const Key &key) const { + if (tree_root == nullptr) throw index_out_of_bound(); + RedBlackTreeNodeType *result = tree_root->Find(key); + if (result == nullptr) throw index_out_of_bound(); + return result->val.second; + } + /** + * access specified element + * Returns a reference to the value that is mapped to a key equivalent to key, + * performing an insertion if such key does not already exist. + */ + T &operator[](const Key &key) { + if (node_count == 0) { + tree_root = + new RedBlackTreeNodeType(value_type(key, T()), nullptr, nullptr, + nullptr, RedBlackTreeNodeType::BLACK); + ++node_count; + return tree_root->val.second; + } + auto result = tree_root->Insert(tree_root, value_type(key, T()), false); + if (result.second) ++node_count; + return result.first->val.second; + } + /** + * behave like at() throw index_out_of_bound if such key does not exist. + */ + const T &operator[](const Key &key) const { return at(key); } + /** + * return a iterator to the beginning + */ + iterator begin() { + if (tree_root == nullptr) return iterator(nullptr, this); + RedBlackTreeNodeType *tmp = tree_root; + while (tmp->left != nullptr) tmp = tmp->left; + return iterator(tmp, this); + } + const_iterator begin() const { return cbegin(); } + const_iterator cbegin() const { + if (tree_root == nullptr) return const_iterator(nullptr, this); + RedBlackTreeNodeType *tmp = tree_root; + while (tmp->left != nullptr) tmp = tmp->left; + return const_iterator(tmp, this); + } + /** + * return a iterator to the end + * in fact, it returns past-the-end. + */ + iterator end() { return iterator(nullptr, this); } + const_iterator end() const { return cend(); } + const_iterator cend() const { return const_iterator(nullptr, this); } + /** + * checks whether the container is empty + * return true if empty, otherwise false. + */ + bool empty() const { return node_count == 0; } + /** + * returns the number of elements. + */ + size_t size() const { return node_count; } + /** + * clears the contents + */ + void clear() { + if (tree_root) tree_root->ReleaseAll(); + delete tree_root; + tree_root = nullptr; + node_count = 0; + } + /** + * insert an element. + * return a pair, the first of the pair is + * the iterator to the new element (or the element that prevented the + * insertion), the second one is true if insert successfully, or false. + */ + pair insert(const value_type &value) { + if (tree_root == nullptr) { + tree_root = new RedBlackTreeNodeType(value, nullptr, nullptr, nullptr, + RedBlackTreeNodeType::BLACK); + node_count = 1; + return pair(iterator(tree_root, this), true); + } + auto result = tree_root->Insert(tree_root, value, false); + if (result.second) ++node_count; + return pair(iterator(result.first, this), result.second); + } + /** + * erase the element at pos. + * + * throw if pos pointed to a bad element (pos == this->end() || pos points an + * element out of this) + */ + void erase(iterator pos) { + if (pos.domain != this || pos.raw_pointer == nullptr) + throw invalid_iterator(); + RedBlackTreeNodeType::DeleteNode(pos.raw_pointer, tree_root); + --node_count; + } + /** + * Returns the number of elements with key + * that compares equivalent to the specified argument, + * which is either 1 or 0 + * since this container does not allow duplicates. + * The default method of check the equivalence is !(a < b || b > a) + */ + size_t count(const Key &key) const { + if (tree_root == nullptr) return 0; + return tree_root->Find(key) == nullptr ? 0 : 1; + } + /** + * Finds an element with key equivalent to key. + * key value of the element to search for. + * Iterator to an element with key equivalent to key. + * If no such element is found, past-the-end (see end()) iterator is + * returned. + */ + iterator find(const Key &key) { + if (tree_root == nullptr) return end(); + return iterator(tree_root->Find(key), this); + } + const_iterator find(const Key &key) const { + if (tree_root == nullptr) return cend(); + return const_iterator(tree_root->Find(key), this); + } +#ifndef NDEBUG + bool RedBlackTreeStructureCheck() { + if (tree_root == nullptr) return node_count == 0; + if (node_count == 0) return false; + std::queue Q; + std::vector NIL_leafs; + size_t actual_node_count = 0; + Q.push(tree_root); + while (!Q.empty()) { + RedBlackTreeNodeType *current = Q.front(); + Q.pop(); + if (current->color == RedBlackTreeNodeType::RED) { + if (current->left != nullptr && + current->left->color == RedBlackTreeNodeType::RED) + return false; + if (current->right != nullptr && + current->right->color == RedBlackTreeNodeType::RED) + return false; + } + if (current->left != nullptr) + Q.push(current->left); + else + NIL_leafs.push_back(current); + if (current->right != nullptr) + Q.push(current->right); + else + NIL_leafs.push_back(current); + ++actual_node_count; + } + if (actual_node_count != node_count) return false; + if (tree_root->color != RedBlackTreeNodeType::BLACK) return false; + if (tree_root->parent != nullptr) return false; + assert(NIL_leafs.size() >= 2); + size_t correct_black_nodes = 1; + RedBlackTreeNodeType *ptr = NIL_leafs[0]; + while (ptr) { + if (ptr->color == RedBlackTreeNodeType::BLACK) ++correct_black_nodes; + ptr = ptr->parent; + } + for (auto ptr : NIL_leafs) { + size_t black_nodes = 1; + while (ptr) { + if (ptr->color == RedBlackTreeNodeType::BLACK) ++black_nodes; + ptr = ptr->parent; + } + if (black_nodes != correct_black_nodes) return false; + } + // Now check whether it is a binary search tree. Use a lambda expression to + // get inorder tree walk. + std::vector key_array; + std::function inorder_walk = + [&](RedBlackTreeNodeType *node) { + if (node->left != nullptr) inorder_walk(node->left); + key_array.push_back(node->val.first); + if (node->right != nullptr) inorder_walk(node->right); + }; + inorder_walk(tree_root); + for (size_t i = 1; i < key_array.size(); ++i) { + if (!comparer(key_array[i - 1], key_array[i])) return false; + } + return true; + } +#endif +}; +// Define the static member comparer. +template +Compare map::comparer = Compare(); + +} // namespace sjtu + +#endif +#include +#include +#include +#include +#include +#include +using namespace std; +typedef long long LL; +typedef long double LDB; +const int kMaxN = 100000 + 10; +int n; +int block_size; +int a[kMaxN], l[kMaxN], r[kMaxN], c[kMaxN]; +int bucket[400][kMaxN * 2]; +int flag[400]; +inline std::pair GetID(int idx) { + return std::pair((idx - 1) / block_size + 1, idx % block_size + 1); +} +int Operate(int L, int R, int c) { + if (R - L + 1 == block_size) { + assert(L % block_size == 1); + int bid = (L - 1) / block_size + 1; + int res = 0; + if (flag[bid] == -1) + res = bucket[bid][c]; + else + res = (c == flag[bid] ? 1 : 0) * block_size; + flag[bid] = c; + return res; + } else { + int res = 0; + int bid = (L - 1) / block_size + 1; + if (flag[bid] == -1) { + for (int i = L; i <= R; i++) { + bucket[bid][a[i]]--; + if (a[i] == c) res++; + a[i] = c; + bucket[bid][c]++; + } + } else { + res = (c == flag[bid] ? 1 : 0) * (R - L + 1); + for (int i = L; i <= R; i++) { + bucket[bid][a[i]]--; + a[i] = c; + bucket[bid][a[i]]++; + } + for (int i = (bid - 1) * block_size + 1; i < L; i++) { + bucket[bid][a[i]]--; + a[i] = flag[bid]; + bucket[bid][a[i]]++; + } + for (int i = R + 1; i <= bid * block_size; i++) { + bucket[bid][a[i]]--; + a[i] = flag[bid]; + bucket[bid][a[i]]++; + } + flag[bid] = -1; + } + return res; + } +} +int main() { +#ifdef local + freopen("pro.in", "r", stdin); +#endif + scanf("%d", &n); + sjtu::map mp; + for (int i = 1; i <= n; i++) { + scanf("%d", &a[i]); + mp[a[i]] = 0; + } + for (int i = 1; i <= n; i++) { + scanf("%d%d%d", &l[i], &r[i], &c[i]); + mp[c[i]] = 0; + } + int tmp = 0; + for (auto &x : mp) x.second = ++tmp; + for (int i = 1; i <= n; i++) { + a[i] = mp[a[i]]; + c[i] = mp[c[i]]; + } + // for(int i=1;i<=n;i++) printf("%d ",a[i]); + // puts(""); + // for(int i=1;i<=n;i++) printf("%d ",c[i]); + // puts(""); + block_size = sqrt(n); + for (int i = 1; i <= n; i++) bucket[GetID(i).first][a[i]]++; + int tot_of_buckets = (n + block_size - 1) / block_size; + for (int i = 1; i <= tot_of_buckets; i++) flag[i] = -1; + for (int i = 1; i <= n; i++) { + int tot = 0; + auto p1 = GetID(l[i]), p2 = GetID(r[i]); + if (p1.first == p2.first) + tot = Operate(l[i], r[i], c[i]); + else { + tot = Operate(l[i], p1.first * block_size, c[i]); + for (int j = p1.first + 1; j < p2.first; j++) + tot += Operate((j - 1) * block_size + 1, j * block_size, c[i]); + tot += Operate((p2.first - 1) * block_size + 1, r[i], c[i]); + } + printf("%d\n", tot); + } + return 0; +} \ No newline at end of file