結果
問題 |
No.3250 最小公倍数
|
ユーザー |
|
提出日時 | 2025-08-29 23:06:39 |
言語 | C++23 (gcc 13.3.0 + boost 1.87.0) |
結果 |
AC
|
実行時間 | 1,572 ms / 2,000 ms |
コード長 | 55,573 bytes |
コンパイル時間 | 2,951 ms |
コンパイル使用メモリ | 200,576 KB |
実行使用メモリ | 56,712 KB |
最終ジャッジ日時 | 2025-08-29 23:07:02 |
合計ジャッジ時間 | 17,475 ms |
ジャッジサーバーID (参考情報) |
judge2 / judge4 |
(要ログイン)
ファイルパターン | 結果 |
---|---|
sample | AC * 1 |
other | AC * 21 |
コンパイルメッセージ
main.cpp:1:9: warning: #pragma once in main file 1 | #pragma once | ^~~~
ソースコード
#pragma once #if defined _CPPUNWIND || defined __cpp_exceptions #define QC_HASH_EXCEPTIONS_ENABLED #endif #include <bit> #include <cstdint> #include <cstring> #include <initializer_list> #include <iterator> #include <limits> #include <memory> #ifdef QC_HASH_EXCEPTIONS_ENABLED #include <stdexcept> #endif #include <string> #include <string_view> #include <type_traits> #include <utility> namespace qc::hash { using u64 = uint64_t; using s64 = int64_t; using f64 = double; using u32 = uint32_t; using s32 = int32_t; using f32 = float; using u16 = uint16_t; using s16 = int16_t; using u8 = uint8_t; using s8 = int8_t; static_assert(std::is_same_v<u64, u64> && std::is_same_v<uintptr_t, u64>, "Unsupported architecture"); inline namespace config { inline constexpr u64 minMapCapacity{16u}; } template<typename T> concept SignedInteger = std::is_same_v<T, s64> || std::is_same_v<T, s32> || std::is_same_v<T, s16> || std::is_same_v<T, s8>; template<typename T> concept UnsignedInteger = std::is_same_v<T, u64> || std::is_same_v<T, u32> || std::is_same_v<T, u16> || std::is_same_v<T, u8>; template<typename T> concept Enum = std::is_enum_v<T>; template<typename T> concept Pointer = std::is_pointer_v<T>; namespace _private { template<u64 size> struct UnsignedHelper; template<> struct UnsignedHelper<1u> { using type = u8; }; template<> struct UnsignedHelper<2u> { using type = u16; }; template<> struct UnsignedHelper<4u> { using type = u32; }; template<> struct UnsignedHelper<8u> { using type = u64; }; } template<u64 size> using Unsigned = typename _private::UnsignedHelper<size>::type; template<u64 elementSize, u64 elementN> struct UnsignedMulti { using Element = Unsigned<elementSize>; Element elements[elementN]; constexpr bool operator==(const UnsignedMulti &) const = default; constexpr UnsignedMulti operator~() const; }; template<typename T> struct IsUniquelyRepresentable : std::bool_constant<std::has_unique_object_representations_v<T>> {}; template<typename T> struct IsUniquelyRepresentable<std::unique_ptr<T>> : std::true_type {}; template<typename T> struct IsUniquelyRepresentable<std::shared_ptr<T>> : std::true_type {}; template<typename T1, typename T2> struct IsUniquelyRepresentable<std::pair<T1, T2>> : std::bool_constant<IsUniquelyRepresentable<T1>::value && IsUniquelyRepresentable<T2>::value> {}; template<typename CharT, typename Traits> struct IsUniquelyRepresentable<std::basic_string_view<CharT, Traits>> : std::false_type {}; template<typename T> concept Rawable = IsUniquelyRepresentable<T>::value; namespace _private { template<typename T> struct RawTypeHelper { using type = Unsigned<sizeof(T)>; }; template<typename T> requires (alignof(T) != sizeof(T) || sizeof(T) > sizeof(uintmax_t)) struct RawTypeHelper<T> { static constexpr u64 align{ alignof(T) > alignof(uintmax_t) ? alignof(uintmax_t) : alignof(T)}; using type = UnsignedMulti<align, sizeof(T) / align>; }; } template<typename T> using RawType = typename _private::RawTypeHelper<T>::type; template<Rawable T> struct IdentityHash; template<typename T> struct IdentityHash<T *>; template<typename T> struct IdentityHash<std::unique_ptr<T>>; template<typename T> struct IdentityHash<std::shared_ptr<T>>; template<typename T> struct FastHash; template<typename T> struct FastHash<T *>; template<typename T> struct FastHash<std::unique_ptr<T>>; template<typename T> struct FastHash<std::shared_ptr<T>>; template<> struct FastHash<std::string>; template<> struct FastHash<std::string_view>; namespace fastHash { template<UnsignedInteger H> [[nodiscard]] constexpr H mix(H v); template<UnsignedInteger H, typename T> [[nodiscard]] constexpr H hash(const T &v); template<UnsignedInteger H> [[nodiscard]] H hash(const void *data, u64 length); } template<typename K, typename KOther> struct IsCompatible : std::bool_constant<std::is_same_v<std::decay_t<K>, std::decay_t<KOther>>> { }; template<SignedInteger K, SignedInteger KOther> struct IsCompatible<K, KOther> : std::bool_constant<sizeof(KOther) <= sizeof(K)> {}; template<UnsignedInteger K, UnsignedInteger KOther> struct IsCompatible<K, KOther> : std::bool_constant<sizeof(KOther) <= sizeof(K)> {}; template<SignedInteger K, UnsignedInteger KOther> struct IsCompatible<K, KOther> : std::bool_constant<sizeof(KOther) < sizeof(K)> {}; template<UnsignedInteger K, SignedInteger KOther> struct IsCompatible<K, KOther> : std::false_type {}; template<typename T, typename TOther> requires (std::is_same_v<std::decay_t<T>, std::decay_t<TOther>> || std::is_base_of_v<T, TOther>) struct IsCompatible<T *, TOther *> : std::true_type {}; template<typename T, typename TOther> requires (std::is_same_v<std::decay_t<T>, std::decay_t<TOther>> || std::is_base_of_v<T, TOther>) struct IsCompatible<std::unique_ptr<T>, TOther *> : std::true_type {}; template<typename T, typename TOther> requires (std::is_same_v<std::decay_t<T>, std::decay_t<TOther>> || std::is_base_of_v<T, TOther>) struct IsCompatible<std::shared_ptr<T>, TOther *> : std::true_type {}; template<typename KOther, typename K> concept Compatible = Rawable<K> && Rawable<KOther> && IsCompatible<K, KOther>::value; struct RawFriend; template<Rawable K, typename V, typename H = IdentityHash<K>, typename A = std::allocator<std::pair<K, V>>> class RawMap; template<Rawable K, typename H = IdentityHash<K>, typename A = std::allocator<K>> using RawSet = RawMap<K, void, H, A>; template<Rawable K, typename V, typename H, typename A> class RawMap { inline static constexpr bool _isSet{std::is_same_v<V, void>}; inline static constexpr bool _isMap{! _isSet}; using E = std::conditional_t<_isSet, K, std::pair<K, V>>; template<bool constant> class _Iterator; friend ::qc::hash::RawFriend; public: static_assert(std::is_move_constructible_v<E>); static_assert(std::is_move_assignable_v<E>); static_assert(std::is_swappable_v<E>); static_assert(requires(const H h, const K k) { u64{h(k)}; }); static_assert(std::is_move_constructible_v<H>); static_assert(std::is_move_assignable_v<H>); static_assert(std::is_swappable_v<H>); static_assert(std::is_move_constructible_v<A>); static_assert(std::is_move_assignable_v<A> || ! std::allocator_traits< A>::propagate_on_container_move_assignment::value); static_assert( std::is_swappable_v<A> || ! std::allocator_traits<A>::propagate_on_container_swap::value); using key_type = K; using mapped_type = V; using value_type = E; using hasher = H; using allocator_type = A; using reference = E &; using const_reference = const E &; using pointer = E *; using const_pointer = const E *; using size_type = u64; using difference_type = s64; using iterator = _Iterator<false>; using const_iterator = _Iterator<true>; explicit RawMap(u64 capacity = minMapCapacity, const H &hash = {}, const A &alloc = {}); RawMap(u64 capacity, const A &alloc); explicit RawMap(const A &alloc); template<typename It> RawMap(It first, It last, u64 capacity = {}, const H &hash = {}, const A &alloc = {}); template<typename It> RawMap(It first, It last, u64 capacity, const A &alloc); RawMap(std::initializer_list<E> elements, u64 capacity = {}, const H &hash = {}, const A &alloc = {}); RawMap(std::initializer_list<E> elements, u64 capacity, const A &alloc); RawMap(const RawMap &other); RawMap(RawMap &&other); RawMap &operator=(std::initializer_list<E> elements); RawMap &operator=(const RawMap &other); RawMap &operator=(RawMap &&other); ~RawMap(); std::pair<iterator, bool> insert(const E &element); std::pair<iterator, bool> insert(E &&element); template<typename It> void insert(It first, It last); void insert(std::initializer_list<E> elements); std::pair<iterator, bool> emplace(const E &element); std::pair<iterator, bool> emplace(E &&element); template<typename K_, typename V_> std::pair<iterator, bool> emplace(K_ &&key, V_ &&value) requires (! std::is_same_v<V, void>); template<typename... KArgs> std::pair<iterator, bool> emplace(KArgs &&...keyArgs) requires (std::is_same_v<V, void>); template<typename... KArgs, typename... VArgs> std::pair<iterator, bool> emplace(std::piecewise_construct_t, std::tuple<KArgs...> &&keyArgs, std::tuple<VArgs...> &&valueArgs) requires (! std::is_same_v<V, void>); template<typename K_, typename... VArgs> std::pair<iterator, bool> try_emplace(K_ &&key, VArgs &&...valueArgs); template<Compatible<K> K_> bool erase(const K_ &key); void erase(iterator position); void clear(); template<Compatible<K> K_> [[nodiscard]] bool contains(const K_ &key) const; template<Compatible<K> K_> [[nodiscard]] u64 count(const K_ &key) const; #ifdef QC_HASH_EXCEPTIONS_ENABLED template<Compatible<K> K_> [[nodiscard]] std::add_lvalue_reference_t<V> at(const K_ &key) requires (! std::is_same_v<V, void>); template<Compatible<K> K_> [[nodiscard]] std::add_lvalue_reference_t<const V> at(const K_ &key) const requires (! std::is_same_v<V, void>); #endif template<Compatible<K> K_> [[nodiscard]] std::add_lvalue_reference_t<V> operator[](const K_ &key) requires (! std::is_same_v<V, void>); template<Compatible<K> K_> [[nodiscard]] std::add_lvalue_reference_t<V> operator[](K_ &&key) requires (! std::is_same_v<V, void>); [[nodiscard]] iterator begin(); [[nodiscard]] const_iterator begin() const; [[nodiscard]] const_iterator cbegin() const; [[nodiscard]] iterator end(); [[nodiscard]] const_iterator end() const; [[nodiscard]] const_iterator cend() const; template<Compatible<K> K_> [[nodiscard]] iterator find(const K_ &key); template<Compatible<K> K_> [[nodiscard]] const_iterator find(const K_ &key) const; template<Compatible<K> K_> [[nodiscard]] u64 slot(const K_ &key) const; void reserve(u64 capacity); void rehash(u64 slotN); void swap(RawMap &other); [[nodiscard]] u64 size() const; [[nodiscard]] bool empty() const; [[nodiscard]] u64 capacity() const; [[nodiscard]] u64 slot_n() const; [[nodiscard]] u64 max_size() const; [[nodiscard]] u64 max_slot_n() const; [[nodiscard]] f32 load_factor() const; [[nodiscard]] f32 max_load_factor() const; [[nodiscard]] const H &hash_function() const; [[nodiscard]] const A &get_allocator() const; private: using _RawKey = RawType<K>; inline static constexpr _RawKey _vacantKey{_RawKey(~_RawKey{})}; inline static constexpr _RawKey _graveKey{_RawKey(~_RawKey{1u})}; inline static constexpr _RawKey _specialKeys[2]{_graveKey, _vacantKey}; inline static constexpr _RawKey _vacantGraveKey{_vacantKey}; inline static constexpr _RawKey _vacantVacantKey{_graveKey}; inline static constexpr _RawKey _vacantSpecialKeys[2]{_vacantGraveKey, _vacantVacantKey}; inline static constexpr _RawKey _terminalKey{0u}; static K &_key(E &element); static const K &_key(const E &element); static bool _isPresent(const _RawKey &key); static bool _isSpecial(const _RawKey &key); u64 _size; u64 _slotN; E *_elements; bool _haveSpecial[2]; H _hash; A _alloc; template<typename KTuple, typename VTuple, u64... kIndices, u64... vIndices> std::pair<iterator, bool> _emplace(KTuple &&kTuple, VTuple &&vTuple, std::index_sequence<kIndices...>, std::index_sequence<vIndices...>); template<bool preserveInvariants> void _clear(); template<Compatible<K> K_> u64 _slot(const K_ &key) const; void _rehash(u64 slotN); template<bool zeroControls> void _allocate(); void _deallocate(); void _clearKeys(); template<bool move> void _forwardData(std::conditional_t<move, RawMap, const RawMap> &other); struct _FindKeyResult1 { E *element; bool isPresent; }; struct _FindKeyResult2 { E *element; bool isPresent; bool isSpecial; unsigned char specialI; }; template<bool insertionForm> using _FindKeyResult = std::conditional_t<insertionForm, _FindKeyResult2, _FindKeyResult1>; template<bool insertionForm, Compatible<K> K_> _FindKeyResult<insertionForm> _findKey(const K_ &key) const; }; template<Rawable K, typename V, typename H, typename A> bool operator==(const RawMap<K, V, H, A> &m1, const RawMap<K, V, H, A> &m2); template<Rawable K, typename V, typename H, typename A> template<bool constant> class RawMap<K, V, H, A>::_Iterator { friend ::qc::hash::RawMap<K, V, H, A>; friend ::qc::hash::RawFriend; using E = std::conditional_t<constant, const RawMap::E, RawMap::E>; public: using iterator_category = std::forward_iterator_tag; using value_type = E; using difference_type = ptrdiff_t; using pointer = E *; using reference = E &; constexpr _Iterator() = default; constexpr _Iterator(const _Iterator &other) = default; template<bool constant_> requires (constant && ! constant_) constexpr _Iterator(const _Iterator<constant_> &other); _Iterator &operator=(const _Iterator &other) = default; template<bool constant_> requires (constant && ! constant_) _Iterator &operator=(const _Iterator<constant_> &other); [[nodiscard]] E &operator*() const; [[nodiscard]] E *operator->() const; _Iterator &operator++(); _Iterator operator++(int); template<bool constant_> [[nodiscard]] bool operator==(const _Iterator<constant_> &other) const; private: E *_element; constexpr _Iterator(E *element); }; } namespace std { template<typename K, typename V, typename H, typename A> void swap(qc::hash::RawMap<K, V, H, A> &a, qc::hash::RawMap<K, V, H, A> &b); } namespace qc::hash { namespace _private { inline constexpr u64 minMapSlotN{minMapCapacity * 2u}; template<UnsignedInteger U, typename T> inline constexpr U getLowBytes(const T &v) { if constexpr(alignof(T) >= sizeof(U)) { return reinterpret_cast<const U &>(v); } else if constexpr(alignof(T) == sizeof(T)) { return reinterpret_cast<const Unsigned<sizeof(T)> &>(v); } else { U result{0u}; using Block = Unsigned<alignof(T) < sizeof(U) ? alignof(T) : sizeof(U)>; constexpr u64 n{(sizeof(T) < sizeof(U) ? sizeof(T) : sizeof(U)) / sizeof(Block)}; const Block *src{reinterpret_cast<const Block *>(&v)}; Block *dst{reinterpret_cast<Block *>(&result)}; if constexpr(std::endian::native == std::endian::big) { constexpr u64 srcBlocks{sizeof(T) / sizeof(Block)}; constexpr u64 dstBlocks{sizeof(U) / sizeof(Block)}; if constexpr(srcBlocks > n) { src += srcBlocks - n; } if constexpr(dstBlocks > n) { dst += dstBlocks - n; } } if constexpr(n >= 1u) dst[0] = src[0]; if constexpr(n >= 2u) dst[1] = src[1]; if constexpr(n >= 3u) dst[2] = src[2]; if constexpr(n >= 4u) dst[3] = src[3]; if constexpr(n >= 5u) dst[4] = src[4]; if constexpr(n >= 6u) dst[5] = src[5]; if constexpr(n >= 7u) dst[6] = src[6]; if constexpr(n >= 8u) dst[7] = src[7]; return result; } } } template<u64 elementSize, u64 elementN> inline constexpr auto UnsignedMulti<elementSize, elementN>::operator~() const -> UnsignedMulti { UnsignedMulti res; for(u64 i{0u}; i < elementN; ++i) { res.elements[i] = Element(~elements[i]); } return res; } template<Rawable T> struct IdentityHash { [[nodiscard]] constexpr u64 operator()(const T &v) const { return _private::getLowBytes<u64>(v); } }; template<typename T> struct IdentityHash<T *> { [[nodiscard]] constexpr u64 operator()(const T *const v) const { constexpr s32 shift{s32(std::bit_width(alignof(T)) - 1u)}; return std::bit_cast<u64>(v) >> shift; } }; template<typename T> struct IdentityHash<std::unique_ptr<T>> : IdentityHash<T *> { using IdentityHash<T *>::operator(); [[nodiscard]] constexpr u64 operator()(const std::unique_ptr<T> &v) const { return (*this)(v.get()); } }; template<typename T> struct IdentityHash<std::shared_ptr<T>> : IdentityHash<T *> { using IdentityHash<T *>::operator(); [[nodiscard]] constexpr u64 operator()(const std::shared_ptr<T> &v) const { return (*this)(v.get()); } }; template<typename T> struct FastHash { [[nodiscard]] constexpr u64 operator()(const T &v) const { return fastHash::hash<u64>(v); } }; template<typename T> struct FastHash<T *> { [[nodiscard]] constexpr u64 operator()(const T *const v) const { return fastHash::hash<u64>(v); } }; template<typename T> struct FastHash<std::unique_ptr<T>> : FastHash<T *> { using FastHash<T *>::operator(); [[nodiscard]] constexpr u64 operator()(const std::unique_ptr<T> &v) const { return (*this)(v.get()); } }; template<typename T> struct FastHash<std::shared_ptr<T>> : FastHash<T *> { using FastHash<T *>::operator(); [[nodiscard]] constexpr u64 operator()(const std::shared_ptr<T> &v) const { return (*this)(v.get()); } }; template<> struct FastHash<std::string> { [[nodiscard]] u64 operator()(const std::string &v) const { return fastHash::hash<u64>(v.c_str(), v.length()); } [[nodiscard]] u64 operator()(const std::string_view &v) const { return fastHash::hash<u64>(v.data(), v.length()); } [[nodiscard]] u64 operator()(const char *v) const { return fastHash::hash<u64>(v, std::strlen(v)); } }; template<> struct FastHash<std::string_view> : FastHash<std::string> {}; namespace fastHash { template<typename H> struct Constants; template<> struct Constants<u64> { inline static constexpr u64 m{0xC6A4A7935BD1E995u}; inline static constexpr s32 r{47}; }; template<> struct Constants<u32> { inline static constexpr u32 m{0x5BD1E995u}; inline static constexpr s32 r{24}; }; template<typename H> inline constexpr H m{Constants<H>::m}; template<typename H> inline constexpr s32 r{Constants<H>::r}; template<UnsignedInteger H> inline constexpr H mix(H v) { v *= m<H>; v ^= v >> r<H>; return v * m<H>; } template<UnsignedInteger H, typename T> inline constexpr H hash(const T &v) { if constexpr(sizeof(T) <= sizeof(H)) { return (H(sizeof(T)) * m<H>)^mix(_private::getLowBytes<H>(v)); } else { return hash<H>(&v, sizeof(T)); } } template<UnsignedInteger H> inline H hash(const void *const data, u64 length) { const std::byte *bytes{static_cast<const std::byte *>(data)}; H h{H(length)}; while(length >= sizeof(H)) { H w; std::memcpy(&w, bytes, sizeof(H)); h *= m<H>; h ^= mix(w); bytes += sizeof(H); length -= sizeof(H); }; if(length) { H w{0u}; std::memcpy(&w, bytes, length); h *= m<H>; h ^= mix(w); } return h; } } template<typename K> inline RawType<K> &_raw(K &key) { return reinterpret_cast<RawType<K> &>(key); } template<typename K> inline const RawType<K> &_raw(const K &key) { return reinterpret_cast<const RawType<K> &>(key); } template<Rawable K, typename V, typename H, typename A> inline RawMap<K, V, H, A>::RawMap(const u64 capacity, const H &hash, const A &alloc) : _size{}, _slotN{capacity <= minMapCapacity ? _private::minMapSlotN : std::bit_ceil(capacity << 1)}, _elements{}, _haveSpecial{}, _hash{hash}, _alloc{alloc} {} template<Rawable K, typename V, typename H, typename A> inline RawMap<K, V, H, A>::RawMap(const u64 capacity, const A &alloc) : RawMap{capacity, H{}, alloc} {} template<Rawable K, typename V, typename H, typename A> inline RawMap<K, V, H, A>::RawMap(const A &alloc) : RawMap{minMapCapacity, H{}, alloc} {} template<Rawable K, typename V, typename H, typename A> template<typename It> inline RawMap<K, V, H, A>::RawMap(const It first, const It last, const u64 capacity, const H &hash, const A &alloc) : RawMap{capacity, hash, alloc} { u64 n{}; for(It it{first}; it != last; ++it, ++n); reserve(n); insert(first, last); } template<Rawable K, typename V, typename H, typename A> template<typename It> inline RawMap<K, V, H, A>::RawMap(const It first, const It last, const u64 capacity, const A &alloc) : RawMap{first, last, capacity, H{}, alloc} {} template<Rawable K, typename V, typename H, typename A> inline RawMap<K, V, H, A>::RawMap(const std::initializer_list<E> elements, u64 capacity, const H &hash, const A &alloc) : RawMap{capacity ? capacity : elements.size(), hash, alloc} { insert(elements); } template<Rawable K, typename V, typename H, typename A> inline RawMap<K, V, H, A>::RawMap(const std::initializer_list<E> elements, const u64 capacity, const A &alloc) : RawMap{elements, capacity, H{}, alloc} {} template<Rawable K, typename V, typename H, typename A> inline RawMap<K, V, H, A>::RawMap(const RawMap &other) : _size{other._size}, _slotN{other._slotN}, _elements{}, _haveSpecial{other._haveSpecial[0], other._haveSpecial[1]}, _hash{other._hash}, _alloc{std::allocator_traits<A>::select_on_container_copy_construction( other._alloc)} { if(_size) { _allocate<false>(); _forwardData<false>(other); } } template<Rawable K, typename V, typename H, typename A> inline RawMap<K, V, H, A>::RawMap(RawMap &&other) : _size{std::exchange(other._size, 0u)}, _slotN{std::exchange(other._slotN, _private::minMapSlotN)}, _elements{std::exchange(other._elements, nullptr)}, _haveSpecial{std::exchange(other._haveSpecial[0], false), std::exchange(other._haveSpecial[1], false)}, _hash{std::move(other._hash)}, _alloc{std::move(other._alloc)} {} template<Rawable K, typename V, typename H, typename A> inline RawMap<K, V, H, A> &RawMap<K, V, H, A>::operator=( const std::initializer_list<E> elements) { return *this = RawMap(elements); } template<Rawable K, typename V, typename H, typename A> inline RawMap<K, V, H, A> &RawMap<K, V, H, A>::operator=(const RawMap &other) { if(&other == this) { return *this; } if(_elements) { _clear<false>(); if(! other._size || _slotN != other._slotN || _alloc != other._alloc) { _deallocate(); } } _size = other._size; _slotN = other._slotN; _haveSpecial[0] = other._haveSpecial[0]; _haveSpecial[1] = other._haveSpecial[1]; _hash = other._hash; if constexpr(std::allocator_traits< A>::propagate_on_container_copy_assignment::value) { _alloc = std::allocator_traits<A>::select_on_container_copy_construction( other._alloc); } if(_size) { if(! _elements) { _allocate<false>(); } _forwardData<false>(other); } return *this; } template<Rawable K, typename V, typename H, typename A> inline RawMap<K, V, H, A> &RawMap<K, V, H, A>::operator=(RawMap &&other) { if(&other == this) { return *this; } if(_elements) { _clear<false>(); _deallocate(); } _size = other._size; _slotN = other._slotN; _haveSpecial[0] = other._haveSpecial[0]; _haveSpecial[1] = other._haveSpecial[1]; _hash = std::move(other._hash); if constexpr(std::allocator_traits< A>::propagate_on_container_move_assignment::value) { _alloc = std::move(other._alloc); } if(_alloc == other._alloc || std::allocator_traits< A>::propagate_on_container_move_assignment::value) { _elements = std::exchange(other._elements, nullptr); other._size = {}; } else { if(_size) { _allocate<false>(); _forwardData<true>(other); other._clear<false>(); other._size = 0u; } if(other._elements) { other._deallocate(); } } other._slotN = _private::minMapSlotN; other._haveSpecial[0] = false; other._haveSpecial[1] = false; return *this; } template<Rawable K, typename V, typename H, typename A> inline RawMap<K, V, H, A>::~RawMap() { if(_elements) { _clear<false>(); _deallocate(); } } template<Rawable K, typename V, typename H, typename A> inline auto RawMap<K, V, H, A>::insert(const E &element) -> std::pair<iterator, bool> { static_assert(std::is_copy_constructible_v<E>); return emplace(element); } template<Rawable K, typename V, typename H, typename A> inline auto RawMap<K, V, H, A>::insert(E &&element) -> std::pair<iterator, bool> { return emplace(std::move(element)); } template<Rawable K, typename V, typename H, typename A> template<typename It> inline void RawMap<K, V, H, A>::insert(It first, const It last) { while(first != last) { emplace(*first); ++first; } } template<Rawable K, typename V, typename H, typename A> inline void RawMap<K, V, H, A>::insert( const std::initializer_list<E> elements) { for(const E &element : elements) { emplace(element); } } template<Rawable K, typename V, typename H, typename A> inline auto RawMap<K, V, H, A>::emplace(const E &element) -> std::pair<iterator, bool> { static_assert(std::is_copy_constructible_v<E>); if constexpr(_isSet) { return try_emplace(element); } else { return try_emplace(element.first, element.second); } } template<Rawable K, typename V, typename H, typename A> inline auto RawMap<K, V, H, A>::emplace(E &&element) -> std::pair<iterator, bool> { if constexpr(_isSet) { return try_emplace(std::move(element)); } else { return try_emplace(std::move(element.first), std::move(element.second)); } } template<Rawable K, typename V, typename H, typename A> template<typename K_, typename V_> inline auto RawMap<K, V, H, A>::emplace(K_ &&key, V_ &&value) -> std::pair<iterator, bool> requires (! std::is_same_v<V, void>) { return try_emplace(std::forward<K_>(key), std::forward<V_>(value)); } template<Rawable K, typename V, typename H, typename A> template<typename... KArgs> inline auto RawMap<K, V, H, A>::emplace(KArgs &&...keyArgs) -> std::pair<iterator, bool> requires (std::is_same_v<V, void>) { return try_emplace(K{std::forward<KArgs>(keyArgs)...}); } template<Rawable K, typename V, typename H, typename A> template<typename... KArgs, typename... VArgs> inline auto RawMap<K, V, H, A>::emplace(const std::piecewise_construct_t, std::tuple<KArgs...> &&keyArgs, std::tuple<VArgs...> &&valueArgs) -> std::pair<iterator, bool> requires (! std::is_same_v<V, void>) { return _emplace(std::move(keyArgs), std::move(valueArgs), std::index_sequence_for<KArgs...>(), std::index_sequence_for<VArgs...>()); } template<Rawable K, typename V, typename H, typename A> template<typename KTuple, typename VTuple, u64... kIndices, u64... vIndices> inline auto RawMap<K, V, H, A>::_emplace(KTuple &&kTuple, VTuple &&vTuple, const std::index_sequence<kIndices...>, const std::index_sequence<vIndices...>) -> std::pair<iterator, bool> { return try_emplace(K{std::move(std::get<kIndices>(kTuple))...}, std::move(std::get<vIndices>(vTuple))...); } template<Rawable K, typename V, typename H, typename A> template<typename K_, typename... VArgs> inline auto RawMap<K, V, H, A>::try_emplace(K_ &&key, VArgs &&...vArgs) -> std::pair<iterator, bool> { static_assert( ! (_isMap && ! sizeof...(VArgs) && ! std::is_default_constructible_v<V>), "The value type must be default constructible in order to pass no value " "arguments"); static_assert(! (_isSet && sizeof...(VArgs)), "Sets do not have values"); if(! _elements) { _allocate<true>(); } _FindKeyResult<true> findResult{_findKey<true>(key)}; if(findResult.isPresent) { return {iterator{findResult.element}, false}; } if(findResult.isSpecial) [[unlikely]] { _haveSpecial[findResult.specialI] = true; } else { if((_size - _haveSpecial[0] - _haveSpecial[1]) >= (_slotN >> 1)) [[unlikely]] { _rehash(_slotN << 1); findResult = _findKey<true>(key); } } if constexpr(_isSet) { std::allocator_traits<A>::construct(_alloc, findResult.element, std::forward<K_>(key)); } else { std::allocator_traits<A>::construct(_alloc, &findResult.element->first, std::forward<K_>(key)); std::allocator_traits<A>::construct(_alloc, &findResult.element->second, std::forward<VArgs>(vArgs)...); } ++_size; return {iterator{findResult.element}, true}; } template<Rawable K, typename V, typename H, typename A> template<Compatible<K> K_> inline bool RawMap<K, V, H, A>::erase(const K_ &key) { if(! _size) { return false; } const auto [element, isPresent]{_findKey<false>(key)}; if(isPresent) { erase(iterator{element}); return true; } else { return false; } } template<Rawable K, typename V, typename H, typename A> inline void RawMap<K, V, H, A>::erase(const iterator position) { E *const eraseElement{position._element}; _RawKey &rawKey{_raw(_key(*eraseElement))}; E *const specialElements{_elements + _slotN}; std::allocator_traits<A>::destroy(_alloc, eraseElement); if(eraseElement < specialElements) { rawKey = _graveKey; } else [[unlikely]] { const auto specialI{eraseElement - specialElements}; _raw(_key(specialElements[specialI])) = _vacantSpecialKeys[specialI]; _haveSpecial[specialI] = false; } --_size; } template<Rawable K, typename V, typename H, typename A> inline void RawMap<K, V, H, A>::clear() { _clear<true>(); } template<Rawable K, typename V, typename H, typename A> template<bool preserveInvariants> inline void RawMap<K, V, H, A>::_clear() { if constexpr(std::is_trivially_destructible_v<E>) { if constexpr(preserveInvariants) { if(_size) { _clearKeys(); _size = {}; _haveSpecial[0] = false; _haveSpecial[1] = false; } } } else { if(_size) { E *element{_elements}; u64 n{}; const u64 regularElementN{_size - _haveSpecial[0] - _haveSpecial[1]}; for(; n < regularElementN; ++element) { _RawKey &rawKey{_raw(_key(*element))}; if(_isPresent(rawKey)) { std::allocator_traits<A>::destroy(_alloc, element); ++n; } if constexpr(preserveInvariants) { rawKey = _vacantKey; } } if constexpr(preserveInvariants) { const E *const endRegularElement{_elements + _slotN}; for(; element < endRegularElement; ++element) { _raw(_key(*element)) = _vacantKey; } } if(_haveSpecial[0]) [[unlikely]] { element = _elements + _slotN; std::allocator_traits<A>::destroy(_alloc, element); if constexpr(preserveInvariants) { _raw(_key(*element)) = _vacantGraveKey; _haveSpecial[0] = false; } } if(_haveSpecial[1]) [[unlikely]] { element = _elements + _slotN + 1; std::allocator_traits<A>::destroy(_alloc, element); if constexpr(preserveInvariants) { _raw(_key(*element)) = _vacantVacantKey; _haveSpecial[1] = false; } } if constexpr(preserveInvariants) { _size = {}; } } } } template<Rawable K, typename V, typename H, typename A> template<Compatible<K> K_> inline bool RawMap<K, V, H, A>::contains(const K_ &key) const { return _size ? _findKey<false>(key).isPresent : false; } template<Rawable K, typename V, typename H, typename A> template<Compatible<K> K_> inline u64 RawMap<K, V, H, A>::count(const K_ &key) const { return contains(key); } #ifdef QC_HASH_EXCEPTIONS_ENABLED template<Rawable K, typename V, typename H, typename A> template<Compatible<K> K_> inline std::add_lvalue_reference_t<V> RawMap<K, V, H, A>::at(const K_ &key) requires (! std::is_same_v<V, void>) { return const_cast<V &>(static_cast<const RawMap *>(this)->at(key)); } template<Rawable K, typename V, typename H, typename A> template<Compatible<K> K_> inline std::add_lvalue_reference_t<const V> RawMap<K, V, H, A>::at( const K_ &key) const requires (! std::is_same_v<V, void>) { if(! _size) { throw std::out_of_range{"Map is empty"}; } const auto [element, isPresent]{_findKey<false>(key)}; if(! isPresent) { throw std::out_of_range{"Element not found"}; } return element->second; } #endif template<Rawable K, typename V, typename H, typename A> template<Compatible<K> K_> inline std::add_lvalue_reference_t<V> RawMap<K, V, H, A>::operator[]( const K_ &key) requires (! std::is_same_v<V, void>) { return try_emplace(key).first->second; } template<Rawable K, typename V, typename H, typename A> template<Compatible<K> K_> inline std::add_lvalue_reference_t<V> RawMap<K, V, H, A>::operator[](K_ &&key) requires (! std::is_same_v<V, void>) { return try_emplace(std::move(key)).first->second; } template<Rawable K, typename V, typename H, typename A> inline auto RawMap<K, V, H, A>::begin() -> iterator { return const_cast<E *>(static_cast<const RawMap *>(this)->begin()._element); } template<Rawable K, typename V, typename H, typename A> inline auto RawMap<K, V, H, A>::begin() const -> const_iterator { if(_size - _haveSpecial[0] - _haveSpecial[1]) [[likely]] { for(const E *element{_elements};; ++element) { if(_isPresent(_raw(_key(*element)))) { return const_iterator{element}; } } } if(_haveSpecial[0]) [[unlikely]] { return const_iterator{_elements + _slotN}; } if(_haveSpecial[1]) [[unlikely]] { return const_iterator{_elements + _slotN + 1}; } return end(); } template<Rawable K, typename V, typename H, typename A> inline auto RawMap<K, V, H, A>::cbegin() const -> const_iterator { return begin(); } template<Rawable K, typename V, typename H, typename A> inline typename RawMap<K, V, H, A>::iterator RawMap<K, V, H, A>::end() { return iterator{}; } template<Rawable K, typename V, typename H, typename A> inline auto RawMap<K, V, H, A>::end() const -> const_iterator { return const_iterator{}; } template<Rawable K, typename V, typename H, typename A> inline auto RawMap<K, V, H, A>::cend() const -> const_iterator { return const_iterator{}; } template<Rawable K, typename V, typename H, typename A> template<Compatible<K> K_> inline auto RawMap<K, V, H, A>::find(const K_ &key) -> iterator { return const_cast<E *>(static_cast<const RawMap *>(this)->find(key)._element); } template<Rawable K, typename V, typename H, typename A> template<Compatible<K> K_> inline auto RawMap<K, V, H, A>::find(const K_ &key) const -> const_iterator { if(! _size) { return cend(); } const auto [element, isPresent]{_findKey<false>(key)}; return isPresent ? const_iterator{element} : cend(); } template<Rawable K, typename V, typename H, typename A> template<Compatible<K> K_> inline u64 RawMap<K, V, H, A>::slot(const K_ &key) const { const _RawKey &rawKey{_raw(key)}; if(_isSpecial(rawKey)) [[unlikely]] { return _slotN + (rawKey == _vacantKey); } else { return _slot(key); } } template<Rawable K, typename V, typename H, typename A> template<Compatible<K> K_> inline u64 RawMap<K, V, H, A>::_slot(const K_ &key) const { return _hash(key) & (_slotN - 1u); } template<Rawable K, typename V, typename H, typename A> inline void RawMap<K, V, H, A>::reserve(const u64 capacity) { rehash(capacity << 1); } template<Rawable K, typename V, typename H, typename A> inline void RawMap<K, V, H, A>::rehash(u64 slotN) { const u64 currentMinSlotN{ _size <= minMapCapacity ? _private::minMapSlotN : ((_size - _haveSpecial[0] - _haveSpecial[1]) << 1)}; if(slotN < currentMinSlotN) { slotN = currentMinSlotN; } else { slotN = std::bit_ceil(slotN); } if(slotN != _slotN) { if(_elements) { _rehash(slotN); } else { _slotN = slotN; } } } template<Rawable K, typename V, typename H, typename A> inline void RawMap<K, V, H, A>::_rehash(const u64 slotN) { const u64 oldSize{_size}; const u64 oldSlotN{_slotN}; E *const oldElements{_elements}; const bool oldHaveSpecial[2]{_haveSpecial[0], _haveSpecial[1]}; _size = {}; _slotN = slotN; _allocate<true>(); _haveSpecial[0] = false; _haveSpecial[1] = false; u64 n{}; const u64 regularElementN{oldSize - oldHaveSpecial[0] - oldHaveSpecial[1]}; for(E *element{oldElements}; n < regularElementN; ++element) { if(_isPresent(_raw(_key(*element)))) { emplace(std::move(*element)); std::allocator_traits<A>::destroy(_alloc, element); ++n; } } if(oldHaveSpecial[0]) [[unlikely]] { E *const oldElement{oldElements + oldSlotN}; std::allocator_traits<A>::construct(_alloc, _elements + _slotN, std::move(*oldElement)); std::allocator_traits<A>::destroy(_alloc, oldElement); ++_size; _haveSpecial[0] = true; } if(oldHaveSpecial[1]) [[unlikely]] { E *const oldElement{oldElements + oldSlotN + 1}; std::allocator_traits<A>::construct(_alloc, _elements + _slotN + 1, std::move(*oldElement)); std::allocator_traits<A>::destroy(_alloc, oldElement); ++_size; _haveSpecial[1] = true; } std::allocator_traits<A>::deallocate(_alloc, oldElements, oldSlotN + 4u); } template<Rawable K, typename V, typename H, typename A> inline void RawMap<K, V, H, A>::swap(RawMap &other) { std::swap(_size, other._size); std::swap(_slotN, other._slotN); std::swap(_elements, other._elements); std::swap(_haveSpecial, other._haveSpecial); std::swap(_hash, other._hash); if constexpr(std::allocator_traits<A>::propagate_on_container_swap::value) { std::swap(_alloc, other._alloc); } } template<Rawable K, typename V, typename H, typename A> inline u64 RawMap<K, V, H, A>::size() const { return _size; } template<Rawable K, typename V, typename H, typename A> inline bool RawMap<K, V, H, A>::empty() const { return ! _size; } template<Rawable K, typename V, typename H, typename A> inline u64 RawMap<K, V, H, A>::capacity() const { return _slotN >> 1; } template<Rawable K, typename V, typename H, typename A> inline u64 RawMap<K, V, H, A>::slot_n() const { return _slotN; } template<Rawable K, typename V, typename H, typename A> inline u64 RawMap<K, V, H, A>::max_size() const { return (max_slot_n() >> 1) + 2u; } template<Rawable K, typename V, typename H, typename A> inline u64 RawMap<K, V, H, A>::max_slot_n() const { return u64{1u} << 63; } template<Rawable K, typename V, typename H, typename A> inline f32 RawMap<K, V, H, A>::load_factor() const { return f32(_size) / f32(_slotN); } template<Rawable K, typename V, typename H, typename A> inline f32 RawMap<K, V, H, A>::max_load_factor() const { return f32(minMapCapacity) / f32(_private::minMapSlotN); } template<Rawable K, typename V, typename H, typename A> inline const H &RawMap<K, V, H, A>::hash_function() const { return _hash; } template<Rawable K, typename V, typename H, typename A> inline const A &RawMap<K, V, H, A>::get_allocator() const { return _alloc; } template<Rawable K, typename V, typename H, typename A> inline K &RawMap<K, V, H, A>::_key(E &element) { if constexpr(_isSet) return element; else return element.first; } template<Rawable K, typename V, typename H, typename A> inline const K &RawMap<K, V, H, A>::_key(const E &element) { if constexpr(_isSet) return element; else return element.first; } template<Rawable K, typename V, typename H, typename A> inline bool RawMap<K, V, H, A>::_isPresent(const _RawKey &key) { return ! _isSpecial(key); } template<Rawable K, typename V, typename H, typename A> inline bool RawMap<K, V, H, A>::_isSpecial(const _RawKey &key) { return key == _vacantKey || key == _graveKey; } template<Rawable K, typename V, typename H, typename A> template<bool zeroKeys> inline void RawMap<K, V, H, A>::_allocate() { _elements = std::allocator_traits<A>::allocate(_alloc, _slotN + 4u); if constexpr(zeroKeys) { _clearKeys(); } _raw(_key(_elements[_slotN + 2])) = _terminalKey; _raw(_key(_elements[_slotN + 3])) = _terminalKey; } template<Rawable K, typename V, typename H, typename A> inline void RawMap<K, V, H, A>::_deallocate() { std::allocator_traits<A>::deallocate(_alloc, _elements, _slotN + 4u); _elements = nullptr; } template<Rawable K, typename V, typename H, typename A> inline void RawMap<K, V, H, A>::_clearKeys() { E *const specialElements{_elements + _slotN}; for(E *element{_elements}; element < specialElements; ++element) { _raw(_key(*element)) = _vacantKey; } _raw(_key(specialElements[0])) = _vacantGraveKey; _raw(_key(specialElements[1])) = _vacantVacantKey; } template<Rawable K, typename V, typename H, typename A> template<bool move> inline void RawMap<K, V, H, A>::_forwardData( std::conditional_t<move, RawMap, const RawMap> &other) { if constexpr(std::is_trivially_copyable_v<E>) { std::memcpy(_elements, other._elements, (_slotN + 2u) * sizeof(E)); } else { using ElementForwardType = std::conditional_t<move, E &&, const E &>; std::conditional_t<move, E, const E> *srcElement{other._elements}; const E *const srcEndElement{other._elements + _slotN}; E *dstElement{_elements}; for(; srcElement < srcEndElement; ++srcElement, ++dstElement) { const _RawKey &rawSrcKey{_raw(_key(*srcElement))}; if(_isPresent(rawSrcKey)) { std::allocator_traits<A>::construct( _alloc, dstElement, static_cast<ElementForwardType>(*srcElement)); } else { _raw(_key(*dstElement)) = rawSrcKey; } } if(_haveSpecial[0]) { std::allocator_traits<A>::construct( _alloc, _elements + _slotN, static_cast<ElementForwardType>(other._elements[_slotN])); } else { _raw(_key(_elements[_slotN])) = _vacantGraveKey; } if(_haveSpecial[1]) { std::allocator_traits<A>::construct( _alloc, _elements + _slotN + 1, static_cast<ElementForwardType>(other._elements[_slotN + 1])); } else { _raw(_key(_elements[_slotN + 1])) = _vacantVacantKey; } } } template<Rawable K, typename V, typename H, typename A> template<bool insertionForm, Compatible<K> K_> inline auto RawMap<K, V, H, A>::_findKey(const K_ &key) const -> _FindKeyResult<insertionForm> { const _RawKey &rawKey{_raw(key)}; if(_isSpecial(rawKey)) [[unlikely]] { const unsigned char specialI{rawKey == _vacantKey}; if constexpr(insertionForm) { return _FindKeyResult<insertionForm>{ .element = _elements + _slotN + specialI, .isPresent = _haveSpecial[specialI], .isSpecial = true, .specialI = specialI}; } else { return _FindKeyResult<insertionForm>{ .element = _elements + _slotN + specialI, .isPresent = _haveSpecial[specialI]}; } } const E *const lastElement{_elements + _slotN}; E *element{_elements + _slot(key)}; E *grave{}; while(true) { const _RawKey &rawSlotKey{_raw(_key(*element))}; if(rawSlotKey == rawKey) { if constexpr(insertionForm) { return {.element = element, .isPresent = true, .isSpecial = false, .specialI = 0u}; } else { return {.element = element, .isPresent = true}; } } if(rawSlotKey == _vacantKey) { if constexpr(insertionForm) { return {.element = grave ? grave : element, .isPresent = false, .isSpecial = false, .specialI = 0u}; } else { return {.element = element, .isPresent = false}; } } if constexpr(insertionForm) { if(rawSlotKey == _graveKey) { grave = element; } } ++element; if(element == lastElement) [[unlikely]] { element = _elements; } } } template<Rawable K, typename V, typename H, typename A> inline bool operator==(const RawMap<K, V, H, A> &m1, const RawMap<K, V, H, A> &m2) { if(m1.size() != m2.size()) { return false; } if(&m1 == &m2) { return true; } const auto endIt{m2.cend()}; for(const auto &element : m1) { if constexpr(std::is_same_v<V, void>) { if(! m2.contains(element)) { return false; } } else { const auto it{m2.find(element.first)}; if(it == endIt || it->second != element.second) { return false; } } } return true; } template<Rawable K, typename V, typename H, typename A> template<bool constant> template<bool constant_> requires (constant && ! constant_) inline constexpr RawMap<K, V, H, A>::_Iterator<constant>::_Iterator( const _Iterator<constant_> &other) : _element{other._element} {} template<Rawable K, typename V, typename H, typename A> template<bool constant> inline constexpr RawMap<K, V, H, A>::_Iterator<constant>::_Iterator( E *const element) : _element{element} {} template<Rawable K, typename V, typename H, typename A> template<bool constant> template<bool constant_> requires (constant && ! constant_) inline auto RawMap<K, V, H, A>::_Iterator<constant>::operator=( const _Iterator<constant_> &other) -> _Iterator & { _element = other._element; return *this; } template<Rawable K, typename V, typename H, typename A> template<bool constant> inline auto RawMap<K, V, H, A>::_Iterator<constant>::operator*() const -> E & { return *_element; } template<Rawable K, typename V, typename H, typename A> template<bool constant> inline auto RawMap<K, V, H, A>::_Iterator<constant>::operator->() const -> E * { return _element; } template<Rawable K, typename V, typename H, typename A> template<bool constant> inline auto RawMap<K, V, H, A>::_Iterator<constant>::operator++() -> _Iterator & { while(true) { ++_element; const _RawKey &rawKey{_raw(_key(*_element))}; if(_isPresent(rawKey)) { if(rawKey == _terminalKey) [[unlikely]] { if(_raw(_key(_element[1])) == _terminalKey) { _element = nullptr; } } return *this; } if(_raw(_key(_element[2])) == _terminalKey) [[unlikely]] { if(_raw(_key(_element[1])) == _terminalKey) [[unlikely]] { if(rawKey == _vacantVacantKey) [[likely]] { _element = nullptr; } return *this; } if(_raw(_key(_element[3])) == _terminalKey) [[likely]] { if(rawKey == _vacantGraveKey) [[likely]] { if(_raw(_key(_element[1])) == _vacantVacantKey) [[likely]] { _element = nullptr; } else { ++_element; } } return *this; } } } } template<Rawable K, typename V, typename H, typename A> template<bool constant> inline auto RawMap<K, V, H, A>::_Iterator<constant>::operator++(int) -> _Iterator { const _Iterator temp{*this}; operator++(); return temp; } template<Rawable K, typename V, typename H, typename A> template<bool constant> template<bool constant_> inline bool RawMap<K, V, H, A>::_Iterator<constant>::operator==( const _Iterator<constant_> &other) const { return _element == other._element; } } namespace std { template<typename K, typename V, typename H, typename A> inline void swap(qc::hash::RawMap<K, V, H, A> &a, qc::hash::RawMap<K, V, H, A> &b) { a.swap(b); } } #define MOD_IS_998 1 #if __has_include("template.hpp") #include "template.hpp" #else #include <algorithm> #include <cassert> #include <concepts> #include <cstdint> #include <functional> #include <ios> #include <iostream> #include <istream> #include <limits> #include <map> #include <ostream> #include <queue> #include <random> #include <ranges> #include <set> #include <stdexcept> #include <string> #include <type_traits> #include <unordered_map> #include <utility> #include <vector> #include <version> #include <atcoder/modint.hpp> using namespace std; using ll = long long; using pall = pair<ll, ll>; template<class T> using vec = vector<T>; template<class T> using veve = vec<vec<T>>; using vell = vec<ll>; using vest = vec<string>; using vebo = basic_string<bool>; using vevell = veve<ll>; template<class T> using mset = multiset<T>; template<class T> using priority_queue_ascend = priority_queue<T, vec<T>, greater<T>>; constexpr ll inf = numeric_limits<ll>::max(); const string sp = " "; const string lf = "\n"; const auto &npos = string::npos; #ifdef MOD_IS_998 constexpr ll MOD = 998244353; #else constexpr ll MOD = 1e9 + 7; #endif const vec<pall> grid_move4 = {{0, 1}, {-1, 0}, {0, -1}, {1, 0}}; const vec<pall> grid_move8 = [] { auto ret = grid_move4; ret.insert(ret.end(), {{-1, 1}, {-1, -1}, {1, -1}, {1, 1}}); return ret; }(); #define cont continue #define br break #define whlie while #define foR for #define reutnr return #define retunr return #define reutrn return #define auot auto #define uato auto #define cosnt const #define conts const #define ocnst const auto &ciN = cin; auto &icn = cin; auto &icN = cin; constexpr bool ture = true; constexpr bool flase = false; namespace rnages = ranges; namespace ra = ranges; using namespace atcoder; using mint = static_modint<MOD>; #define times(N) \ static_assert(is_integral_v<decltype((N) + 0)>, \ "times(): N must be integral"); \ assert((N) >= 0); \ for(typedef decltype((N) + 0) _int; \ [[maybe_unused]] const _int _i : views::iota((_int)0, (N))) #define tiems times #define itmes times template<int M> istream &operator>>(istream &in, static_modint<M> &i) { ll tmp; in >> tmp; i = tmp; return in; } template<int M> ostream &operator<<(ostream &out, const static_modint<M> &i) { return out << i.val(); } template<class T, class U> istream &operator>>(istream &in, pair<T, U> &p) { return in >> p.first >> p.second; } template<class T, class U> ostream &operator<<(ostream &out, const pair<T, U> &p) { return out << p.first << sp << p.second; } template<class T> istream &operator>>(istream &in, vec<T> &v) { for(auto &&e : v) { in >> e; } return in; } struct debug_stream { template<class T> debug_stream &operator<<([[maybe_unused]] const T &x) { #ifndef ONLINE_JUDGE clog << x; #endif return *this; } debug_stream &operator<<([[maybe_unused]] ostream &(*f)(ostream &)) { #ifndef ONLINE_JUDGE clog << f; #endif return *this; } }; template<class T> concept out_stream = same_as<ostream, T> || same_as<debug_stream, T>; debug_stream clog_; #define clog clog_ template<class... Ts> istream &in(Ts &...vecs) { static_assert(sizeof...(vecs) != 0, "myfunc::in(): At least one vector must be provided"); const set sizes = {vecs.size()...}; if(sizes.size() > 1) { throw invalid_argument("myfunc::in(): All vectors must have the same size"); } times(*sizes.begin()) { ((cin >> vecs[_i]), ...); } return cin; } void out(ranges::range auto v, const string delim, out_stream auto &out) { ranges::for_each(v, [&](const auto &e) { out << e << delim; }); } void out(ranges::range auto v, const string delim) { out(v, delim, cout); } [[nodiscard]] const string &yesno(const bool cond, const string &yes = "Yes", const string &no = "No") noexcept { if(cond) return yes; return no; } [[nodiscard]] uint64_t randint(const uint64_t mi, const uint64_t ma) noexcept { static random_device seed; static mt19937_64 mt(seed()); if(mi > ma) [[unlikely]] return randint(ma, mi); if(mi == ma) [[unlikely]] return mi; const uint64_t w = ma - mi; uint64_t r; do { r = mt(); } while(mt.max() - mt.max() % w <= r); return r % w + mi; } template<class T, class U> requires common_with<T, U> [[nodiscard]] constexpr auto min(T &&a, U &&b) noexcept { return std::min<common_type_t<T, U>>(std::forward<T>(a), std::forward<U>(b)); } template<class T, class U> requires common_with<T, U> [[nodiscard]] constexpr auto max(T &&a, U &&b) noexcept { return std::max<common_type_t<T, U>>(std::forward<T>(a), std::forward<U>(b)); } template<class... Args> [[nodiscard]] auto reduce(const ranges::range auto &r, Args &&...args) { return reduce(ranges::cbegin(r), ranges::cend(r), forward<Args>(args)...); } [[nodiscard]] constexpr ll powll(ll a, ll b, const ll m = inf) { if(b < 0) [[unlikely]] throw invalid_argument("powll(): exponent less than zero"); if(m < 1) [[unlikely]] throw invalid_argument("powll(): modulo less than one"); a %= m; ll ret = 1; while(b) { if(b % 2) ret *= a, ret %= m; a *= a, a %= m; b /= 2; } return ret; } template<class T, class U> requires assignable_from<T &, U> && totally_ordered_with<T, U> bool mini(T &var, U &&val) noexcept { const bool cmp = var > val; if(cmp) var = val; return cmp; } template<class T, class U> requires assignable_from<T &, U> && totally_ordered_with<T, U> bool maxi(T &var, U &&val) noexcept { const bool cmp = var < val; if(cmp) var = val; return cmp; } class [[nodiscard]] grid_base { public: grid_base(const ll h, const ll w) noexcept : height(h), width(w) {} [[nodiscard]] ll operator()(const ll i, const ll j) const noexcept { if(! isvalid(i, j)) return -1; return i * width + j; } [[nodiscard]] ll operator()(const pall &p) const noexcept { return (*this)(p.first, p.second); } protected: bool isvalid(const ll i, const ll j) const noexcept { return 0 <= i && 0 <= j && i < height && j < width; } const ll height, width; }; class [[nodiscard]] grid_seen : public grid_base { public: grid_seen(const ll h, const ll w) : grid_base(h, w) { visited = vebo(h * w, false); } [[nodiscard]] bool &seen(const ll i, const ll j) & { if(! isvalid(i, j)) [[unlikely]] throw out_of_range("grid_seen::seen(): out of range"); return visited[i * width + j]; } [[nodiscard]] bool &sen(const ll i, const ll j) & { return seen(i, j); } [[nodiscard]] bool &seen(const pall &p) & { return seen(p.first, p.second); } [[nodiscard]] bool &sen(const pall &p) & { return seen(p); } private: vebo visited; }; using grid_lite = grid_base; template<auto defval, class... Args> requires is_convertible_v<decltype(defval), typename map<Args...>::mapped_type> class default_map : public map<Args...> { using Map = map<Args...>; public: #ifdef __cpp_lib_associative_heterogeneous_insertion template<convertible_to<typename Map::key_type> U> requires requires(Map::key_compare c, Map::key_type t, U u) { c(t, u); c(u, t); } Map::mapped_type &operator[](const U &key) { Map::try_emplace(key, defval); return Map::operator[](key); } template<convertible_to<typename Map::key_type> U> requires requires(Map::key_compare c, Map::key_type t, U u) { c(t, u); c(u, t); } Map::mapped_type &operator[](const U &&key) { Map::try_emplace(key, defval); return Map::operator[](key); } #else Map::mapped_type &operator[](const Map::key_type &key) { Map::try_emplace(key, defval); return Map::operator[](key); } Map::mapped_type &operator[](const Map::key_type &&key) { Map::try_emplace(key, defval); return Map::operator[](key); } #endif }; template<auto defval, class... Args> requires is_convertible_v<decltype(defval), typename unordered_map<Args...>::mapped_type> class default_unordered_map : public unordered_map<Args...> { using Map = unordered_map<Args...>; public: #ifdef __cpp_lib_associative_heterogeneous_insertion template<class U> requires requires(Map::hasher h, U u) { h(u); } Map::mapped_type &operator[](const U &key) { Map::try_emplace(key, defval); return Map::operator[](key); } template<class U> requires requires(Map::hasher h, U u) { h(u); } Map::mapped_type &operator[](const U &&key) { Map::try_emplace(key, defval); return Map::operator[](key); } #else Map::mapped_type &operator[](const Map::key_type &key) { Map::try_emplace(key, defval); return Map::operator[](key); } Map::mapped_type &operator[](const Map::key_type &&key) { Map::try_emplace(key, defval); return Map::operator[](key); } #endif }; template<class T, class U> requires requires(mset<T>::key_compare c, T t, U u) { c(t, u); } auto erase_single(mset<T> &mset, U &&v) { const auto it = mset.find(v); if(it == mset.end()) [[unlikely]] throw invalid_argument("erase_single(): why v not in mset!?!?"); return mset.erase(it); } void solve(); #endif int main(void) { cin.tie(nullptr); ios::sync_with_stdio(false); ll t = 1; times(t) solve(); return 0; } #include <algorithm> #include <cmath> #include <cstddef> #include <vector> using namespace std; using ll = long long; class linear_sieve { public: linear_sieve(const ll n) { minfactor.resize(n + 1, 0); minfactor[0] = 0; minfactor[1] = 1; primes.reserve(ll(n / log(n) * 1.15)); for(ll i = 2; i <= n; i++) { if(! minfactor[i]) minfactor[i] = i, primes.push_back(i); for(size_t j = 0; j != primes.size() && primes[j] <= minfactor[i]; j++) { if(i * primes[j] > n) break; minfactor[i * primes[j]] = primes[j]; } } } vector<ll> minfactor, primes; }; class segment_sieve : public linear_sieve { public: segment_sieve(const ll l, const ll r) : linear_sieve((ll)sqrt(r) + 10) { isprime = vector<bool>(r - l + 1, true); for(const auto &p : primes) { ll cur = max(p * p, (l + p - 1) / p * p) - l; for(; cur < r - l + 1; cur += p) { isprime[cur] = false; } } } vector<bool> isprime; }; void solve() { const auto lpf = linear_sieve(1e6 + 10).minfactor; ll n; cin >> n; vell a(n); cin >> a; vevell nei(n); times(n - 1) { ll u, v; cin >> u >> v; u--, v--; nei[u].push_back(v); nei[v].push_back(u); } vec<mint> ans(n); vebo sen(n, false); const auto dfs = [&](auot &&self, const ll i) -> qc::hash::RawMap<ll, ll> { sen[i] = ture; qc::hash::RawMap<ll, ll> m; mint mp = a[i]; { ll tmp = a[i]; while(tmp != 1) { m[lpf[tmp]]++; tmp /= lpf[tmp]; } } clog << "in v" << i << lf; for(const auot &e : nei[i]) { if(sen[e]) cont; auto m2 = self(self, e); if(m.size() < m2.size()) { swap(m, m2); mp = ans[e]; } clog << "mp: " << mp << lf; clog << "m: "; out(m, sp, clog), clog << lf; clog << "m2: "; out(m2, sp, clog), clog << lf; for(const auto &[p, e] : m2) { if(m.contains(p) && m[p] >= e) cont; mp *= mint(p).pow(e - m[p]); m[p] = e; } clog << "mp: " << mp << lf; clog << "m: "; out(m, sp, clog), clog << lf; } ans[i] = mp; retunr m; }; dfs(dfs, 0); out(ans, lf); }