結果
問題 | No.2634 Tree Distance 3 |
ユーザー | suisen |
提出日時 | 2024-02-17 00:50:21 |
言語 | C++17 (gcc 12.3.0 + boost 1.83.0) |
結果 |
AC
|
実行時間 | 1,449 ms / 3,000 ms |
コード長 | 44,870 bytes |
コンパイル時間 | 3,489 ms |
コンパイル使用メモリ | 250,072 KB |
実行使用メモリ | 42,832 KB |
最終ジャッジ日時 | 2024-09-28 23:18:26 |
合計ジャッジ時間 | 56,459 ms |
ジャッジサーバーID (参考情報) |
judge1 / judge4 |
(要ログイン)
テストケース
テストケース表示入力 | 結果 | 実行時間 実行使用メモリ |
---|---|---|
testcase_00 | AC | 1,103 ms
32,736 KB |
testcase_01 | AC | 1,225 ms
32,744 KB |
testcase_02 | AC | 1,063 ms
32,904 KB |
testcase_03 | AC | 1,098 ms
33,412 KB |
testcase_04 | AC | 1,150 ms
34,272 KB |
testcase_05 | AC | 1,223 ms
32,528 KB |
testcase_06 | AC | 1,164 ms
33,264 KB |
testcase_07 | AC | 1,208 ms
32,260 KB |
testcase_08 | AC | 525 ms
34,032 KB |
testcase_09 | AC | 508 ms
34,364 KB |
testcase_10 | AC | 525 ms
34,504 KB |
testcase_11 | AC | 489 ms
34,260 KB |
testcase_12 | AC | 451 ms
34,608 KB |
testcase_13 | AC | 568 ms
34,900 KB |
testcase_14 | AC | 477 ms
34,884 KB |
testcase_15 | AC | 527 ms
35,176 KB |
testcase_16 | AC | 1,020 ms
27,584 KB |
testcase_17 | AC | 543 ms
18,312 KB |
testcase_18 | AC | 706 ms
21,344 KB |
testcase_19 | AC | 844 ms
26,764 KB |
testcase_20 | AC | 230 ms
10,460 KB |
testcase_21 | AC | 1,449 ms
32,596 KB |
testcase_22 | AC | 1,335 ms
32,352 KB |
testcase_23 | AC | 1,407 ms
33,012 KB |
testcase_24 | AC | 1,172 ms
32,740 KB |
testcase_25 | AC | 1,282 ms
32,580 KB |
testcase_26 | AC | 1,338 ms
33,228 KB |
testcase_27 | AC | 1,441 ms
33,004 KB |
testcase_28 | AC | 1,359 ms
32,760 KB |
testcase_29 | AC | 1,362 ms
33,496 KB |
testcase_30 | AC | 1,069 ms
33,036 KB |
testcase_31 | AC | 1,131 ms
33,300 KB |
testcase_32 | AC | 1,095 ms
33,460 KB |
testcase_33 | AC | 710 ms
26,272 KB |
testcase_34 | AC | 118 ms
7,824 KB |
testcase_35 | AC | 386 ms
16,808 KB |
testcase_36 | AC | 208 ms
10,896 KB |
testcase_37 | AC | 445 ms
18,700 KB |
testcase_38 | AC | 6 ms
6,820 KB |
testcase_39 | AC | 6 ms
6,816 KB |
testcase_40 | AC | 4 ms
6,820 KB |
testcase_41 | AC | 4 ms
6,820 KB |
testcase_42 | AC | 4 ms
6,820 KB |
testcase_43 | AC | 262 ms
14,236 KB |
testcase_44 | AC | 167 ms
9,884 KB |
testcase_45 | AC | 813 ms
30,856 KB |
testcase_46 | AC | 521 ms
19,800 KB |
testcase_47 | AC | 978 ms
31,664 KB |
testcase_48 | AC | 1,036 ms
32,652 KB |
testcase_49 | AC | 1,052 ms
33,288 KB |
testcase_50 | AC | 1,066 ms
33,708 KB |
testcase_51 | AC | 1,077 ms
32,280 KB |
testcase_52 | AC | 1,052 ms
33,508 KB |
testcase_53 | AC | 5 ms
6,816 KB |
testcase_54 | AC | 5 ms
6,816 KB |
testcase_55 | AC | 4 ms
6,816 KB |
testcase_56 | AC | 4 ms
6,816 KB |
testcase_57 | AC | 5 ms
6,820 KB |
testcase_58 | AC | 2 ms
6,820 KB |
testcase_59 | AC | 1 ms
6,820 KB |
testcase_60 | AC | 948 ms
32,132 KB |
testcase_61 | AC | 884 ms
33,264 KB |
testcase_62 | AC | 892 ms
33,376 KB |
testcase_63 | AC | 329 ms
40,568 KB |
testcase_64 | AC | 212 ms
27,168 KB |
testcase_65 | AC | 310 ms
39,812 KB |
testcase_66 | AC | 89 ms
13,812 KB |
testcase_67 | AC | 72 ms
12,544 KB |
testcase_68 | AC | 350 ms
42,832 KB |
testcase_69 | AC | 341 ms
41,804 KB |
testcase_70 | AC | 345 ms
42,800 KB |
ソースコード
#include <bits/stdc++.h> namespace suisen { template <class T> bool chmin(T& x, const T& y) { return y >= x ? false : (x = y, true); } template <class T> bool chmax(T& x, const T& y) { return y <= x ? false : (x = y, true); } template <class T> constexpr int pow_m1(T n) { return -(n & 1) | 1; } template <class T> constexpr T fld(const T x, const T y) { T q = x / y, r = x % y; return q - ((x ^ y) < 0 and (r != 0)); } template <class T> constexpr T cld(const T x, const T y) { T q = x / y, r = x % y; return q + ((x ^ y) > 0 and (r != 0)); } } namespace suisen::macro { #define IMPL_REPITER(cond) auto& begin() { return *this; } auto end() { return nullptr; } auto& operator*() { return _val; } auto& operator++() { return _val += _step, *this; } bool operator!=(std::nullptr_t) { return cond; } template <class Int, class IntL = Int, class IntStep = Int, std::enable_if_t<(std::is_signed_v<Int> == std::is_signed_v<IntL>), std::nullptr_t> = nullptr> struct rep_impl { Int _val; const Int _end, _step; rep_impl(Int n) : rep_impl(0, n) {} rep_impl(IntL l, Int r, IntStep step = 1) : _val(l), _end(r), _step(step) {} IMPL_REPITER((_val < _end)) }; template <class Int, class IntL = Int, class IntStep = Int, std::enable_if_t<(std::is_signed_v<Int> == std::is_signed_v<IntL>), std::nullptr_t> = nullptr> struct rrep_impl { Int _val; const Int _end, _step; rrep_impl(Int n) : rrep_impl(0, n) {} rrep_impl(IntL l, Int r) : _val(r - 1), _end(l), _step(-1) {} rrep_impl(IntL l, Int r, IntStep step) : _val(l + fld<Int>(r - l - 1, step) * step), _end(l), _step(-step) {} IMPL_REPITER((_val >= _end)) }; template <class Int, class IntStep = Int> struct repinf_impl { Int _val; const Int _step; repinf_impl(Int l, IntStep step = 1) : _val(l), _step(step) {} IMPL_REPITER((true)) }; #undef IMPL_REPITER } #include <iostream> #include <limits> #include <type_traits> namespace suisen { template <typename ...Constraints> using constraints_t = std::enable_if_t<std::conjunction_v<Constraints...>, std::nullptr_t>; template <typename T, typename = std::nullptr_t> struct bitnum { static constexpr int value = 0; }; template <typename T> struct bitnum<T, constraints_t<std::is_integral<T>>> { static constexpr int value = std::numeric_limits<std::make_unsigned_t<T>>::digits; }; template <typename T> static constexpr int bitnum_v = bitnum<T>::value; template <typename T, size_t n> struct is_nbit { static constexpr bool value = bitnum_v<T> == n; }; template <typename T, size_t n> static constexpr bool is_nbit_v = is_nbit<T, n>::value; template <typename T, typename = std::nullptr_t> struct safely_multipliable { using type = T; }; template <typename T> struct safely_multipliable<T, constraints_t<std::is_signed<T>, is_nbit<T, 32>>> { using type = long long; }; template <typename T> struct safely_multipliable<T, constraints_t<std::is_signed<T>, is_nbit<T, 64>>> { using type = __int128_t; }; template <typename T> struct safely_multipliable<T, constraints_t<std::is_unsigned<T>, is_nbit<T, 32>>> { using type = unsigned long long; }; template <typename T> struct safely_multipliable<T, constraints_t<std::is_unsigned<T>, is_nbit<T, 64>>> { using type = __uint128_t; }; template <typename T> using safely_multipliable_t = typename safely_multipliable<T>::type; template <typename T, typename = void> struct rec_value_type { using type = T; }; template <typename T> struct rec_value_type<T, std::void_t<typename T::value_type>> { using type = typename rec_value_type<typename T::value_type>::type; }; template <typename T> using rec_value_type_t = typename rec_value_type<T>::type; template <typename T> class is_iterable { template <typename T_> static auto test(T_ e) -> decltype(e.begin(), e.end(), std::true_type{}); static std::false_type test(...); public: static constexpr bool value = decltype(test(std::declval<T>()))::value; }; template <typename T> static constexpr bool is_iterable_v = is_iterable<T>::value; template <typename T> class is_writable { template <typename T_> static auto test(T_ e) -> decltype(std::declval<std::ostream&>() << e, std::true_type{}); static std::false_type test(...); public: static constexpr bool value = decltype(test(std::declval<T>()))::value; }; template <typename T> static constexpr bool is_writable_v = is_writable<T>::value; template <typename T> class is_readable { template <typename T_> static auto test(T_ e) -> decltype(std::declval<std::istream&>() >> e, std::true_type{}); static std::false_type test(...); public: static constexpr bool value = decltype(test(std::declval<T>()))::value; }; template <typename T> static constexpr bool is_readable_v = is_readable<T>::value; } // namespace suisen namespace suisen::io { template <typename IStream, std::enable_if_t<std::conjunction_v<std::is_base_of<std::istream, std::remove_reference_t<IStream>>, std::negation<std::is_const<std::remove_reference_t<IStream>>>>, std::nullptr_t> = nullptr> struct InputStream { private: using istream_type = std::remove_reference_t<IStream>; IStream is; struct { InputStream* is; template <typename T> operator T() { T e; *is >> e; return e; } } _reader{ this }; public: template <typename IStream_> InputStream(IStream_ &&is) : is(std::move(is)) {} template <typename IStream_> InputStream(IStream_ &is) : is(is) {} template <typename T> InputStream& operator>>(T& e) { if constexpr (suisen::is_readable_v<T>) is >> e; else _read(e); return *this; } auto read() { return _reader; } template <typename Head, typename... Tail> void read(Head& head, Tail &...tails) { ((*this >> head) >> ... >> tails); } istream_type& get_stream() { return is; } private: static __uint128_t _stou128(const std::string& s) { __uint128_t ret = 0; for (char c : s) if ('0' <= c and c <= '9') ret = 10 * ret + c - '0'; return ret; } static __int128_t _stoi128(const std::string& s) { return (s[0] == '-' ? -1 : +1) * _stou128(s); } void _read(__uint128_t& v) { v = _stou128(std::string(_reader)); } void _read(__int128_t& v) { v = _stoi128(std::string(_reader)); } template <typename T, typename U> void _read(std::pair<T, U>& a) { *this >> a.first >> a.second; } template <size_t N = 0, typename ...Args> void _read(std::tuple<Args...>& a) { if constexpr (N < sizeof...(Args)) *this >> std::get<N>(a), _read<N + 1>(a); } template <typename Iterable, std::enable_if_t<suisen::is_iterable_v<Iterable>, std::nullptr_t> = nullptr> void _read(Iterable& a) { for (auto& e : a) *this >> e; } }; template <typename IStream> InputStream(IStream &&) -> InputStream<IStream>; template <typename IStream> InputStream(IStream &) -> InputStream<IStream&>; InputStream cin{ std::cin }; auto read() { return cin.read(); } template <typename Head, typename... Tail> void read(Head& head, Tail &...tails) { cin.read(head, tails...); } } // namespace suisen::io namespace suisen { using io::read; } // namespace suisen namespace suisen::io { template <typename OStream, std::enable_if_t<std::conjunction_v<std::is_base_of<std::ostream, std::remove_reference_t<OStream>>, std::negation<std::is_const<std::remove_reference_t<OStream>>>>, std::nullptr_t> = nullptr> struct OutputStream { private: using ostream_type = std::remove_reference_t<OStream>; OStream os; public: template <typename OStream_> OutputStream(OStream_ &&os) : os(std::move(os)) {} template <typename OStream_> OutputStream(OStream_ &os) : os(os) {} template <typename T> OutputStream& operator<<(const T& e) { if constexpr (suisen::is_writable_v<T>) os << e; else _print(e); return *this; } void print() { *this << '\n'; } template <typename Head, typename... Tail> void print(const Head& head, const Tail &...tails) { *this << head, ((*this << ' ' << tails), ...), *this << '\n'; } template <typename Iterable, std::enable_if_t<suisen::is_iterable_v<Iterable>, std::nullptr_t> = nullptr> void print_all(const Iterable& v, std::string sep = " ", std::string end = "\n") { for (auto it = v.begin(); it != v.end();) if (*this << *it; ++it != v.end()) *this << sep; *this << end; } ostream_type& get_stream() { return os; } private: void _print(__uint128_t value) { char buffer[41], *d = std::end(buffer); do *--d = '0' + (value % 10), value /= 10; while (value); os.rdbuf()->sputn(d, std::end(buffer) - d); } void _print(__int128_t value) { if (value < 0) *this << '-'; _print(__uint128_t(value < 0 ? -value : value)); } template <typename T, typename U> void _print(const std::pair<T, U>& a) { *this << a.first << ' ' << a.second; } template <size_t N = 0, typename ...Args> void _print(const std::tuple<Args...>& a) { if constexpr (N < std::tuple_size_v<std::tuple<Args...>>) { if constexpr (N) *this << ' '; *this << std::get<N>(a), _print<N + 1>(a); } } template <typename Iterable, std::enable_if_t<suisen::is_iterable_v<Iterable>, std::nullptr_t> = nullptr> void _print(const Iterable& a) { print_all(a, " ", ""); } }; template <typename OStream_> OutputStream(OStream_ &&) -> OutputStream<OStream_>; template <typename OStream_> OutputStream(OStream_ &) -> OutputStream<OStream_&>; OutputStream cout{ std::cout }, cerr{ std::cerr }; template <typename... Args> void print(const Args &... args) { cout.print(args...); } template <typename Iterable, std::enable_if_t<suisen::is_iterable_v<Iterable>, std::nullptr_t> = nullptr> void print_all(const Iterable& v, const std::string& sep = " ", const std::string& end = "\n") { cout.print_all(v, sep, end); } } // namespace suisen::io namespace suisen { using io::print, io::print_all; } // namespace suisen namespace suisen { template <class T, class ToKey, class CompKey = std::less<>, std::enable_if_t<std::conjunction_v<std::is_invocable<ToKey, T>, std::is_invocable_r<bool, CompKey, std::invoke_result_t<ToKey, T>, std::invoke_result_t<ToKey, T>>>, std::nullptr_t> = nullptr> auto comparator(const ToKey& to_key, const CompKey& comp_key = std::less<>()) { return [=](const T& x, const T& y) { return comp_key(to_key(x), to_key(y)); }; } template <class Compare, std::enable_if_t<std::is_invocable_r_v<bool, Compare, int, int>, std::nullptr_t> = nullptr> std::vector<int> sorted_indices(int n, const Compare& compare) { std::vector<int> p(n); return std::iota(p.begin(), p.end(), 0), std::sort(p.begin(), p.end(), compare), p; } template <class ToKey, std::enable_if_t<std::is_invocable_v<ToKey, int>, std::nullptr_t> = nullptr> std::vector<int> sorted_indices(int n, const ToKey& to_key) { return sorted_indices(n, comparator<int>(to_key)); } template <class T, class Comparator> auto priority_queue_with_comparator(const Comparator& comparator) { return std::priority_queue<T, std::vector<T>, Comparator>{ comparator }; } template <class Iterable, std::enable_if_t<suisen::is_iterable_v<Iterable>, std::nullptr_t> = nullptr> void sort_unique_erase(Iterable& a) { std::sort(a.begin(), a.end()), a.erase(std::unique(a.begin(), a.end()), a.end()); } template <size_t D> struct Dim : std::array<int, D> { template <typename ...Ints> Dim(const Ints& ...ns) : std::array<int, D>::array{ static_cast<int>(ns)... } {} }; template <typename ...Ints> Dim(const Ints& ...) -> Dim<sizeof...(Ints)>; template <class T, size_t D, size_t I = 0> auto ndvec(const Dim<D> &ns, const T& value = {}) { if constexpr (I + 1 < D) { return std::vector(ns[I], ndvec<T, D, I + 1>(ns, value)); } else { return std::vector<T>(ns[I], value); } } } namespace suisen { using int128 = __int128_t; using uint128 = __uint128_t; template <class T> using min_priority_queue = std::priority_queue<T, std::vector<T>, std::greater<T>>; template <class T> using max_priority_queue = std::priority_queue<T, std::vector<T>, std::less<T>>; } namespace suisen { const std::string Yes = "Yes", No = "No", YES = "YES", NO = "NO"; } #ifdef LOCAL # define debug(...) debug_impl(#__VA_ARGS__, __VA_ARGS__) template <class H, class... Ts> void debug_impl(const char* s, const H& h, const Ts&... t) { suisen::io::cerr << "[\033[32mDEBUG\033[m] " << s << ": " << h, ((suisen::io::cerr << ", " << t), ..., (suisen::io::cerr << "\n")); } #else # define debug(...) void(0) #endif #define FOR(e, v) for (auto &&e : v) #define CFOR(e, v) for (const auto &e : v) #define REP(i, ...) CFOR(i, suisen::macro::rep_impl(__VA_ARGS__)) #define RREP(i, ...) CFOR(i, suisen::macro::rrep_impl(__VA_ARGS__)) #define REPINF(i, ...) CFOR(i, suisen::macro::repinf_impl(__VA_ARGS__)) #define LOOP(n) for ([[maybe_unused]] const auto& _ : suisen::macro::rep_impl(n)) #define ALL(iterable) std::begin(iterable), std::end(iterable) using namespace suisen; using namespace std; struct io_setup { io_setup(int precision = 20) { std::ios::sync_with_stdio(false), std::cin.tie(nullptr); std::cout << std::fixed << std::setprecision(precision); } } io_setup_{}; constexpr int iinf = std::numeric_limits<int>::max() / 2; constexpr long long linf = std::numeric_limits<long long>::max() / 2; #include <deque> #include <queue> #include <tuple> #include <vector> #include <algorithm> #include <cassert> #include <optional> #include <utility> namespace suisen { namespace internal::csr_graph { struct graph_base_tag {}; } struct directed_graph_tag : internal::csr_graph::graph_base_tag {}; struct undirected_graph_tag : internal::csr_graph::graph_base_tag {}; template <typename T> struct is_graph_tag { static constexpr bool value = std::is_base_of_v<internal::csr_graph::graph_base_tag, T>; }; template <typename T> constexpr bool is_graph_tag_v = is_graph_tag<T>::value; template <typename WeightType = void> struct Graph { template <typename GraphTag, typename, std::enable_if_t<is_graph_tag_v<GraphTag>, std::nullptr_t>> friend struct GraphBuilder; using weight_type = WeightType; static constexpr bool weighted = std::negation_v<std::is_same<weight_type, void>>; using weight_type_or_1 = std::conditional_t<weighted, weight_type, int>; using input_edge_type = std::conditional_t<weighted, std::tuple<int, int, weight_type>, std::pair<int, int>>; private: using internal_edge_type = std::conditional_t<weighted, std::pair<int, weight_type>, int>; struct Edge : public internal_edge_type { using internal_edge_type::internal_edge_type; operator int() const { return std::get<0>(*this); } }; public: using edge_type = std::conditional_t<weighted, Edge, int>; private: struct AdjacentList { friend struct Graph; using value_type = edge_type; using iterator = typename std::vector<value_type>::iterator; using const_iterator = typename std::vector<value_type>::const_iterator; using reverse_iterator = typename std::vector<value_type>::reverse_iterator; using const_reverse_iterator = typename std::vector<value_type>::const_reverse_iterator; AdjacentList() = default; int size() const { return _siz; } bool empty() const { return _siz == 0; } int capacity() const { return _cap; } value_type& operator[](int i) { return *(begin() + i); } const value_type& operator[](int i) const { return *(cbegin() + i); } value_type& at(uint32_t i) { assert(i < _siz); return *(begin() + i); } const value_type& at(uint32_t i) const { assert(i < _siz); return *(cbegin() + i); } value_type* data() { return _g->_edges.data() + _offset; } const value_type* data() const { return _g->_edges.data() + _offset; } iterator begin() const { return _g->_edges.begin() + _offset; } iterator end() const { return begin() + _siz; } const_iterator cbegin() const { return _g->_edges.cbegin() + _offset; } const_iterator cend() const { return cbegin() + _siz; } reverse_iterator rbegin() const { return _g->_edges.rbegin() + (_g->_edges.size() - (_offset + _siz)); } reverse_iterator rend() const { return rbegin() + _siz; } const_reverse_iterator crbegin() const { return _g->_edges.crbegin() + (_g->_edges.size() - (_offset + _siz)); } const_reverse_iterator crend() const { return crbegin() + _siz; } void erase(const_iterator pos) { erase(pos, std::next(pos)); } void erase(const_iterator first, const_iterator last) { const int num = last - first, k = first - cbegin(); assert(num >= 0); if (num == 0) return; assert(0 <= k and k <= _siz - num); std::move(begin() + k + num, end(), begin() + k); _siz -= num; } void pop_back() { assert(_siz); --_siz; } void clear() { _siz = 0; } const value_type& back() const { return *--cend(); } value_type& back() { return *--end(); } const value_type& front() const { return *cbegin(); } value_type& front() { return *begin(); } void push_back(const value_type& x) { ++_siz; assert(_siz <= _cap); back() = x; } template <typename ...Args> void emplace_back(Args &&...args) { ++_siz; assert(_siz <= _cap); back() = value_type(std::forward<Args>(args)...); } void insert(const_iterator pos, const value_type& x) { emplace(pos, x); } void insert(const_iterator pos, int num, const value_type& x) { const int k = pos - cbegin(); assert(0 <= k and k <= _siz); std::fill(begin() + k, shift_back(begin() + k, num), x); } template <class RandomAccessIterator> auto insert(const_iterator pos, RandomAccessIterator first, RandomAccessIterator last) -> decltype(*first++, last - first, void()) { const int num = last - first, k = pos - cbegin(); assert(0 <= k and k <= _siz); shift_back(begin() + k, num); std::copy(first, last, begin() + k); } void insert(const_iterator pos, std::initializer_list<value_type> il) { insert(pos, il.begin(), il.end()); } template <typename ...Args> void emplace(const_iterator pos, Args &&...args) { const int k = pos - cbegin(); assert(0 <= k and k <= _siz); *--shift_back(begin() + k) = value_type(std::forward<Args>(args)...); } private: mutable Graph* _g; int _cap; int _offset; int _siz; iterator shift_back(iterator pos, int num = 1) { _siz += num; assert(_siz <= _cap); return std::move_backward(pos, end() - num, end()); } }; public: using adjacent_list = AdjacentList; Graph() = default; template <typename GraphTag, std::enable_if_t<is_graph_tag_v<GraphTag>, std::nullptr_t> = nullptr> Graph(const int n, const std::vector<input_edge_type>& edges, GraphTag, std::vector<int> cap = {}) : _n(n), _adj(_n) { static constexpr bool undirected = std::is_same_v<undirected_graph_tag, GraphTag>; for (const auto& e : edges) { const int u = std::get<0>(e); ++_adj[u]._siz; if constexpr (undirected) { const int v = std::get<1>(e); ++_adj[v]._siz; } } if (cap.empty()) cap.resize(_n, std::numeric_limits<int>::max()); int edge_num = 0; for (int i = 0; i < _n; ++i) { _adj[i]._g = this; _adj[i]._cap = std::min(_adj[i]._siz, cap[i]); _adj[i]._offset = edge_num; edge_num += _adj[i]._siz; } _edges.resize(edge_num); std::vector<typename std::vector<edge_type>::iterator> ptr(_n); for (int i = 0; i < _n; ++i) ptr[i] = _adj[i].begin(); for (const auto& e : edges) { const int u = std::get<0>(e); const int v = std::get<1>(e); if constexpr (weighted) { const weight_type& w = std::get<2>(e); *ptr[u]++ = { v, w }; if constexpr (undirected) *ptr[v]++ = { u, w }; } else { *ptr[u]++ = v; if constexpr (undirected) *ptr[v]++ = u; } } } Graph(const std::vector<std::vector<edge_type>>& g) : Graph(g.size(), make_edges(g), directed_graph_tag{}) {} static Graph create_directed_graph(const int n, const std::vector<input_edge_type>& edges, const std::vector<int>& cap = {}) { return Graph(n, edges, directed_graph_tag{}, cap); } static Graph create_undirected_graph(const int n, const std::vector<input_edge_type>& edges, const std::vector<int>& cap = {}) { return Graph(n, edges, undirected_graph_tag{}, cap); } adjacent_list& operator[](int i) { _adj[i]._g = this; return _adj[i]; } const adjacent_list& operator[](int i) const { _adj[i]._g = const_cast<Graph*>(this); return _adj[i]; } int size() const { return _n; } void shrink_to_fit() { int edge_num = 0; for (const auto& l : _adj) edge_num += l.size(); std::vector<edge_type> new_edges(edge_num); auto it = new_edges.begin(); for (int i = 0; i < _n; ++i) { int nl = it - new_edges.begin(); it = std::move(_adj[i].begin(), _adj[i].end(), it); _adj[i]._offset = nl; _adj[i]._cap = _adj[i]._siz; } _edges.swap(new_edges); } static weight_type_or_1 get_weight(const edge_type& edge) { if constexpr (weighted) return std::get<1>(edge); else return 1; } Graph reversed(const std::vector<int>& cap = {}) const { std::vector<input_edge_type> edges; for (int i = 0; i < _n; ++i) { for (const auto& edge : (*this)[i]) { if constexpr (weighted) edges.emplace_back(std::get<0>(edge), i, std::get<1>(edge)); else edges.emplace_back(edge, i); } } return Graph(_n, std::move(edges), directed_graph_tag{}, cap); } struct DFSTree { std::vector<int> par; std::vector<int> pre_ord, pst_ord; Graph tree, back; }; DFSTree dfs_tree(int start = 0) const { std::vector<input_edge_type> tree_edge, back_edge; std::vector<int> pre(_n), pst(_n); auto pre_it = pre.begin(), pst_it = pst.begin(); std::vector<int> eid(_n, -1), par(_n, -2); std::vector<std::optional<weight_type_or_1>> par_w(_n, std::nullopt); for (int i = 0; i < _n; ++i) { int cur = (start + i) % _n; if (par[cur] != -2) continue; par[cur] = -1; while (cur >= 0) { ++eid[cur]; if (eid[cur] == 0) *pre_it++ = cur; if (eid[cur] == _adj[cur].size()) { *pst_it++ = cur; cur = par[cur]; } else { const auto &e = _adj[cur][eid[cur]]; weight_type_or_1 w = get_weight(e); int nxt = e; if (par[nxt] == -2) { tree_edge.emplace_back(make_edge(cur, e)); par[nxt] = cur; par_w[nxt] = std::move(w); cur = nxt; } else if (eid[nxt] != _adj[nxt].size()) { if (par[cur] != nxt or par_w[cur] != w or not std::exchange(par_w[cur], std::nullopt).has_value()) { back_edge.emplace_back(make_edge(cur, e)); } } } } } Graph tree = create_directed_graph(_n, tree_edge); Graph back = create_directed_graph(_n, back_edge); return DFSTree{ std::move(par), std::move(pre), std::move(pst), std::move(tree), std::move(back) }; } private: int _n; std::vector<adjacent_list> _adj; std::vector<edge_type> _edges; static std::vector<input_edge_type> make_edges(const std::vector<std::vector<edge_type>>& g) { const int n = g.size(); std::vector<input_edge_type> edges; for (int i = 0; i < n; ++i) for (const auto& e : g[i]) { edges.emplace_back(make_edge(i, e)); } return edges; } static input_edge_type make_edge(int i, const edge_type& e) { if constexpr (weighted) return { i, std::get<0>(e), std::get<1>(e) }; else return { i, e }; } }; template <typename GraphTag> Graph(int, std::vector<std::pair<int, int>>, GraphTag, std::vector<int> = {})->Graph<void>; template <typename WeightType, typename GraphTag> Graph(int, std::vector<std::tuple<int, int, WeightType>>, GraphTag, std::vector<int> = {})->Graph<WeightType>; Graph(std::vector<std::vector<int>>)->Graph<void>; template <typename WeightType> Graph(std::vector<std::vector<std::pair<int, WeightType>>>)->Graph<WeightType>; template <typename GraphTag, typename WeightType = void, std::enable_if_t<is_graph_tag_v<GraphTag>, std::nullptr_t> = nullptr> struct GraphBuilder { using graph_tag = GraphTag; using weight_type = WeightType; using edge_type = typename Graph<weight_type>::input_edge_type; GraphBuilder(int n = 0) : _n(n) {} void add_edge(const edge_type& edge) { check_not_moved(); _edges.push_back(edge); } template <typename ...Args> void emplace_edge(Args &&...args) { check_not_moved(); _edges.emplace_back(std::forward<Args>(args)...); } template <typename EdgeContainer, std::enable_if_t<std::is_constructible_v<edge_type, typename EdgeContainer::value_type>, std::nullptr_t> = nullptr> void add_edges(const EdgeContainer& edges) { for (const auto& edge : edges) add_edge(edge); } template <bool move_edges = true> Graph<weight_type> build() { if constexpr (move_edges) { _moved = true; return Graph<weight_type>(_n, std::move(_edges), graph_tag{}); } else { return Graph<weight_type>(_n, _edges, graph_tag{}); } } Graph<weight_type> build_without_move() { return build<false>(); } static Graph<weight_type> build(const int n, const std::vector<edge_type>& edges) { GraphBuilder builder(n); builder.add_edges(edges); return builder.build(); } private: int _n; std::vector<edge_type> _edges; bool _moved = false; void check_not_moved() { if (not _moved) return; std::cerr << "[\033[31mERROR\033[m] Edges are already moved. If you want to add edges after calling build() and build another graph, you should use build_without_move() instead." << std::endl; assert(false); } }; template <typename WeightType = void> using DirectedGraphBuilder = GraphBuilder<directed_graph_tag, WeightType>; template <typename WeightType = void> using UndirectedGraphBuilder = GraphBuilder<undirected_graph_tag, WeightType>; template <typename Weight, std::enable_if_t<std::negation_v<std::is_same<Weight, void>>, std::nullptr_t> = nullptr> using WeightedGraph = Graph<Weight>; using UnweightedGraph = Graph<void>; template <typename T> struct is_weighted_graph { static constexpr bool value = false; }; template <typename WeightType> struct is_weighted_graph<Graph<WeightType>> { static constexpr bool value = Graph<WeightType>::weighted; }; template <typename T> constexpr bool is_weighted_graph_v = is_weighted_graph<T>::value; template <typename T> struct is_unweighted_graph { static constexpr bool value = false; }; template <typename WeightType> struct is_unweighted_graph<Graph<WeightType>> { static constexpr bool value = not Graph<WeightType>::weighted; }; template <typename T> constexpr bool is_unweighted_graph_v = is_unweighted_graph<T>::value; } // namespace suisen namespace suisen { namespace internal { template <typename WeightType = void> struct CentroidDecomposition : Graph<WeightType> { friend struct CentroidDecompositionUnweighted; template <typename WeightType_, std::enable_if_t<not std::is_same_v<WeightType_, void>, std::nullptr_t>> friend struct CentroidDecompositionWeighted; using graph_type = Graph<WeightType>; using weight_type = WeightType; CentroidDecomposition(const graph_type& g) : graph_type(g), n(this->size()), cpar(n, -1), cdep(n, std::numeric_limits<int>::max()), csiz(n) { build(); } int dct_parent(int i) const { return cpar[i]; } int dct_depth(int i) const { return cdep[i]; } int dct_size(int i) const { return csiz[i]; } private: int n; std::vector<int> cpar; std::vector<int> cdep; std::vector<int> csiz; void build() { std::vector<int> eid(n, 0); cpar[0] = -1, csiz[0] = n; std::deque<std::tuple<int, int>> dq{ { 0, 0 } }; while (dq.size()) { const auto [r, dep] = dq.front(); const int siz = csiz[r], prev_ctr = cpar[r]; dq.pop_front(); int c = -1; eid[r] = 0, csiz[r] = 1, cpar[r] = -1; for (int cur = r;;) { for (const int edge_num = int((*this)[cur].size());;) { if (eid[cur] == edge_num) { if (csiz[cur] * 2 > siz) { c = cur; } else { const int nxt = cpar[cur]; csiz[nxt] += csiz[cur]; cur = nxt; } break; } const int nxt = (*this)[cur][eid[cur]++]; if (cdep[nxt] >= dep and nxt != cpar[cur]) { eid[nxt] = 0, csiz[nxt] = 1, cpar[nxt] = cur; cur = nxt; break; } } if (c >= 0) break; } for (int v : (*this)[c]) if (cdep[v] >= dep) { if (cpar[c] == v) cpar[v] = c, csiz[v] = siz - csiz[c]; dq.emplace_back(v, dep + 1); } cpar[c] = prev_ctr, cdep[c] = dep, csiz[c] = siz; } } }; struct CentroidDecompositionUnweighted : internal::CentroidDecomposition<void> { using base_type = internal::CentroidDecomposition<void>; using base_type::base_type; std::vector<std::vector<std::pair<int, int>>> collect(int root, int root_val = 0) const { std::vector<std::vector<std::pair<int, int>>> res{ { { root, root_val } } }; for (int sub_root : (*this)[root]) if (this->cdep[sub_root] > this->cdep[root]) { res.emplace_back(); std::deque<std::tuple<int, int, int>> dq{ { sub_root, root, root_val + 1 } }; while (dq.size()) { auto [u, p, w] = dq.front(); dq.pop_front(); res.back().emplace_back(u, w); for (int v : (*this)[u]) if (v != p and this->cdep[v] > this->cdep[root]) { dq.emplace_back(v, u, w + 1); } } std::copy(res.back().begin(), res.back().end(), std::back_inserter(res.front())); } return res; } }; template <typename WeightType, std::enable_if_t<not std::is_same_v<WeightType, void>, std::nullptr_t> = nullptr> struct CentroidDecompositionWeighted : internal::CentroidDecomposition<WeightType> { using base_type = internal::CentroidDecomposition<WeightType>; using base_type::base_type; using weight_type = typename base_type::weight_type; template <typename Op, std::enable_if_t<std::is_invocable_r_v<weight_type, Op, weight_type, weight_type>, std::nullptr_t> = nullptr> std::vector<std::vector<std::pair<int, weight_type>>> collect(int root, Op op, weight_type root_val) const { std::vector<std::vector<std::pair<int, weight_type>>> res{ { { root, root_val } } }; for (auto [sub_root, ew] : (*this)[root]) if (this->cdep[sub_root] > this->cdep[root]) { res.emplace_back(); std::deque<std::tuple<int, int, weight_type>> dq{ { sub_root, root, op(root_val, ew) } }; while (dq.size()) { auto [u, p, w] = dq.front(); dq.pop_front(); res.back().emplace_back(u, w); for (auto [v, ew] : (*this)[u]) if (v != p and this->cdep[v] > this->cdep[root]) { dq.emplace_back(v, u, op(w, ew)); } } std::copy(res.back().begin(), res.back().end(), std::back_inserter(res.front())); } return res; } }; } using CentroidDecompositionUnweighted = internal::CentroidDecompositionUnweighted; template <typename WeightType, std::enable_if_t<not std::is_same_v<WeightType, void>, std::nullptr_t> = nullptr> using CentroidDecompositionWeighted = internal::CentroidDecompositionWeighted<WeightType>; } // namespace suisen namespace suisen { template <typename T> class CoordinateCompressorBuilder { public: struct Compressor { public: static constexpr int absent = -1; // default constructor Compressor() : _xs(std::vector<T>{}) {} // Construct from strictly sorted vector Compressor(const std::vector<T> &xs) : _xs(xs) { assert(is_strictly_sorted(xs)); } // Return the number of distinct keys. int size() const { return _xs.size(); } // Check if the element is registered. bool has_key(const T &e) const { return std::binary_search(_xs.begin(), _xs.end(), e); } // Compress the element. if not registered, returns `default_value`. (default: Compressor::absent) int comp(const T &e, int default_value = absent) const { const int res = min_geq_index(e); return res != size() and _xs[res] == e ? res : default_value; } // Restore the element from the index. T decomp(const int compressed_index) const { return _xs[compressed_index]; } // Compress the element. Equivalent to call `comp(e)` int operator[](const T &e) const { return comp(e); } // Return the minimum registered value greater than `e`. if not exists, return `default_value`. T min_gt(const T &e, const T &default_value) const { auto it = std::upper_bound(_xs.begin(), _xs.end(), e); return it == _xs.end() ? default_value : *it; } // Return the minimum registered value greater than or equal to `e`. if not exists, return `default_value`. T min_geq(const T &e, const T &default_value) const { auto it = std::lower_bound(_xs.begin(), _xs.end(), e); return it == _xs.end() ? default_value : *it; } // Return the maximum registered value less than `e`. if not exists, return `default_value` T max_lt(const T &e, const T &default_value) const { auto it = std::upper_bound(_xs.rbegin(), _xs.rend(), e, std::greater<T>()); return it == _xs.rend() ? default_value : *it; } // Return the maximum registered value less than or equal to `e`. if not exists, return `default_value` T max_leq(const T &e, const T &default_value) const { auto it = std::lower_bound(_xs.rbegin(), _xs.rend(), e, std::greater<T>()); return it == _xs.rend() ? default_value : *it; } // Return the compressed index of the minimum registered value greater than `e`. if not exists, return `compressor.size()`. int min_gt_index(const T &e) const { return std::upper_bound(_xs.begin(), _xs.end(), e) - _xs.begin(); } // Return the compressed index of the minimum registered value greater than or equal to `e`. if not exists, return `compressor.size()`. int min_geq_index(const T &e) const { return std::lower_bound(_xs.begin(), _xs.end(), e) - _xs.begin(); } // Return the compressed index of the maximum registered value less than `e`. if not exists, return -1. int max_lt_index(const T &e) const { return int(_xs.rend() - std::upper_bound(_xs.rbegin(), _xs.rend(), e, std::greater<T>())) - 1; } // Return the compressed index of the maximum registered value less than or equal to `e`. if not exists, return -1. int max_leq_index(const T &e) const { return int(_xs.rend() - std::lower_bound(_xs.rbegin(), _xs.rend(), e, std::greater<T>())) - 1; } private: std::vector<T> _xs; static bool is_strictly_sorted(const std::vector<T> &v) { return std::adjacent_find(v.begin(), v.end(), std::greater_equal<T>()) == v.end(); } }; CoordinateCompressorBuilder() : _xs(std::vector<T>{}) {} explicit CoordinateCompressorBuilder(const std::vector<T> &xs) : _xs(xs) {} explicit CoordinateCompressorBuilder(std::vector<T> &&xs) : _xs(std::move(xs)) {} template <typename Gen, constraints_t<std::is_invocable_r<T, Gen, int>> = nullptr> CoordinateCompressorBuilder(const int n, Gen generator) { reserve(n); for (int i = 0; i < n; ++i) push(generator(i)); } // Attempt to preallocate enough memory for specified number of elements. void reserve(int n) { _xs.reserve(n); } // Add data. void push(const T &first) { _xs.push_back(first); } // Add data. void push(T &&first) { _xs.push_back(std::move(first)); } // Add data in the range of [first, last). template <typename Iterator> auto push(const Iterator &first, const Iterator &last) -> decltype(std::vector<T>{}.push_back(*first), void()) { for (auto it = first; it != last; ++it) _xs.push_back(*it); } // Add all data in the container. Equivalent to `push(iterable.begin(), iterable.end())`. template <typename Iterable> auto push(const Iterable &iterable) -> decltype(std::vector<T>{}.push_back(*iterable.begin()), void()) { push(iterable.begin(), iterable.end()); } // Add data. template <typename ...Args> void emplace(Args &&...args) { _xs.emplace_back(std::forward<Args>(args)...); } // Build compressor. auto build() { std::sort(_xs.begin(), _xs.end()), _xs.erase(std::unique(_xs.begin(), _xs.end()), _xs.end()); return Compressor {_xs}; } // Build compressor from vector. static auto build(const std::vector<T> &xs) { return CoordinateCompressorBuilder(xs).build(); } // Build compressor from vector. static auto build(std::vector<T> &&xs) { return CoordinateCompressorBuilder(std::move(xs)).build(); } // Build compressor from generator. template <typename Gen, constraints_t<std::is_invocable_r<T, Gen, int>> = nullptr> static auto build(const int n, Gen generator) { return CoordinateCompressorBuilder<T>(n, generator).build(); } private: std::vector<T> _xs; }; } // namespace suisen #include <atcoder/segtree> using S = int; S op(S x, S y) { return max(x, y); } S e() { return -1e9; } void solve() { int n; read(n); vector<int> a(n); read(a); UnweightedGraph g = [&] { std::vector<std::vector<int>> g(n); LOOP(n - 1) { int u, v; read(u, v); --u, --v; g[u].push_back(v); g[v].push_back(u); } return UnweightedGraph(g); }(); vector<int> comp_id(n); vector<int> dep(n); CentroidDecompositionUnweighted cd(g); vector<int> ans(n); for (int root = 0; root < n; ++root) { vector<pair<int, int>> vs; auto cmps = cd.collect(root); const int c = cmps.size(); REP(i, c) { for (auto [v, d] : cmps[i]) { vs.emplace_back(a[v], v); comp_id[v] = i; dep[v] = d; } } vs.emplace_back(a[root], root); comp_id[root] = c; dep[root] = 0; const int siz = vs.size(); atcoder::segtree<int, op, e> seg(c + 1); sort(ALL(vs), greater<>()); for (int l = 0; l < siz;) { int r = l; while (r < siz and vs[l].first == vs[r].first) { int v = vs[r++].second; int p = comp_id[v]; seg.set(p, op(seg.get(p), dep[v])); } for (int i = l; i < r; ++i) { int v = vs[i].second; int p = comp_id[v]; ans[v] = op(ans[v], dep[v] + op(seg.prod(0, p), seg.prod(p + 1, c + 1))); } l = r; } } print(ans); } int main() { int test_case_num = 1; // read(test_case_num); LOOP(test_case_num) solve(); return 0; }