#include namespace suisen { template bool chmin(T& x, const T& y) { return y >= x ? false : (x = y, true); } template bool chmax(T& x, const T& y) { return y <= x ? false : (x = y, true); } template constexpr int pow_m1(T n) { return -(n & 1) | 1; } template 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 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 == std::is_signed_v), 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 == std::is_signed_v), 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(r - l - 1, step) * step), _end(l), _step(-step) {} IMPL_REPITER((_val >= _end)) }; template 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 #include #include namespace suisen { template using constraints_t = std::enable_if_t, std::nullptr_t>; template struct bitnum { static constexpr int value = 0; }; template struct bitnum>> { static constexpr int value = std::numeric_limits>::digits; }; template static constexpr int bitnum_v = bitnum::value; template struct is_nbit { static constexpr bool value = bitnum_v == n; }; template static constexpr bool is_nbit_v = is_nbit::value; template struct safely_multipliable { using type = T; }; template struct safely_multipliable, is_nbit>> { using type = long long; }; template struct safely_multipliable, is_nbit>> { using type = __int128_t; }; template struct safely_multipliable, is_nbit>> { using type = unsigned long long; }; template struct safely_multipliable, is_nbit>> { using type = __uint128_t; }; template using safely_multipliable_t = typename safely_multipliable::type; template struct rec_value_type { using type = T; }; template struct rec_value_type> { using type = typename rec_value_type::type; }; template using rec_value_type_t = typename rec_value_type::type; template class is_iterable { template 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()))::value; }; template static constexpr bool is_iterable_v = is_iterable::value; template class is_writable { template static auto test(T_ e) -> decltype(std::declval() << e, std::true_type{}); static std::false_type test(...); public: static constexpr bool value = decltype(test(std::declval()))::value; }; template static constexpr bool is_writable_v = is_writable::value; template class is_readable { template static auto test(T_ e) -> decltype(std::declval() >> e, std::true_type{}); static std::false_type test(...); public: static constexpr bool value = decltype(test(std::declval()))::value; }; template static constexpr bool is_readable_v = is_readable::value; } // namespace suisen namespace suisen::io { template >, std::negation>>>, std::nullptr_t> = nullptr> struct InputStream { private: using istream_type = std::remove_reference_t; IStream is; struct { InputStream* is; template operator T() { T e; *is >> e; return e; } } _reader{ this }; public: template InputStream(IStream_ &&is) : is(std::move(is)) {} template InputStream(IStream_ &is) : is(is) {} template InputStream& operator>>(T& e) { if constexpr (suisen::is_readable_v) is >> e; else _read(e); return *this; } auto read() { return _reader; } template 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 void _read(std::pair& a) { *this >> a.first >> a.second; } template void _read(std::tuple& a) { if constexpr (N < sizeof...(Args)) *this >> std::get(a), _read(a); } template , std::nullptr_t> = nullptr> void _read(Iterable& a) { for (auto& e : a) *this >> e; } }; template InputStream(IStream &&) -> InputStream; template InputStream(IStream &) -> InputStream; InputStream cin{ std::cin }; auto read() { return cin.read(); } template void read(Head& head, Tail &...tails) { cin.read(head, tails...); } } // namespace suisen::io namespace suisen { using io::read; } // namespace suisen namespace suisen::io { template >, std::negation>>>, std::nullptr_t> = nullptr> struct OutputStream { private: using ostream_type = std::remove_reference_t; OStream os; public: template OutputStream(OStream_ &&os) : os(std::move(os)) {} template OutputStream(OStream_ &os) : os(os) {} template OutputStream& operator<<(const T& e) { if constexpr (suisen::is_writable_v) os << e; else _print(e); return *this; } void print() { *this << '\n'; } template void print(const Head& head, const Tail &...tails) { *this << head, ((*this << ' ' << tails), ...), *this << '\n'; } template , 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 void _print(const std::pair& a) { *this << a.first << ' ' << a.second; } template void _print(const std::tuple& a) { if constexpr (N < std::tuple_size_v>) { if constexpr (N) *this << ' '; *this << std::get(a), _print(a); } } template , std::nullptr_t> = nullptr> void _print(const Iterable& a) { print_all(a, " ", ""); } }; template OutputStream(OStream_ &&) -> OutputStream; template OutputStream(OStream_ &) -> OutputStream; OutputStream cout{ std::cout }, cerr{ std::cerr }; template void print(const Args &... args) { cout.print(args...); } template , 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 , std::enable_if_t, std::is_invocable_r, std::invoke_result_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 , std::nullptr_t> = nullptr> std::vector sorted_indices(int n, const Compare& compare) { std::vector p(n); return std::iota(p.begin(), p.end(), 0), std::sort(p.begin(), p.end(), compare), p; } template , std::nullptr_t> = nullptr> std::vector sorted_indices(int n, const ToKey& to_key) { return sorted_indices(n, comparator(to_key)); } template auto priority_queue_with_comparator(const Comparator& comparator) { return std::priority_queue, Comparator>{ comparator }; } template , 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 struct Dim : std::array { template Dim(const Ints& ...ns) : std::array::array{ static_cast(ns)... } {} }; template Dim(const Ints& ...) -> Dim; template auto ndvec(const Dim &ns, const T& value = {}) { if constexpr (I + 1 < D) { return std::vector(ns[I], ndvec(ns, value)); } else { return std::vector(ns[I], value); } } } namespace suisen { using int128 = __int128_t; using uint128 = __uint128_t; template using min_priority_queue = std::priority_queue, std::greater>; template using max_priority_queue = std::priority_queue, std::less>; } namespace suisen { const std::string Yes = "Yes", No = "No", YES = "YES", NO = "NO"; } #ifdef LOCAL # define debug(...) debug_impl(#__VA_ARGS__, __VA_ARGS__) template 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::max() / 2; constexpr long long linf = std::numeric_limits::max() / 2; #include #include #include #include #include #include #include #include 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 struct is_graph_tag { static constexpr bool value = std::is_base_of_v; }; template constexpr bool is_graph_tag_v = is_graph_tag::value; template struct Graph { template , std::nullptr_t>> friend struct GraphBuilder; using weight_type = WeightType; static constexpr bool weighted = std::negation_v>; using weight_type_or_1 = std::conditional_t; using input_edge_type = std::conditional_t, std::pair>; private: using internal_edge_type = std::conditional_t, 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; private: struct AdjacentList { friend struct Graph; using value_type = edge_type; using iterator = typename std::vector::iterator; using const_iterator = typename std::vector::const_iterator; using reverse_iterator = typename std::vector::reverse_iterator; using const_reverse_iterator = typename std::vector::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 void emplace_back(Args &&...args) { ++_siz; assert(_siz <= _cap); back() = value_type(std::forward(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 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 il) { insert(pos, il.begin(), il.end()); } template 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)...); } 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 , std::nullptr_t> = nullptr> Graph(const int n, const std::vector& edges, GraphTag, std::vector cap = {}) : _n(n), _adj(_n) { static constexpr bool undirected = std::is_same_v; 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::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::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>& g) : Graph(g.size(), make_edges(g), directed_graph_tag{}) {} static Graph create_directed_graph(const int n, const std::vector& edges, const std::vector& cap = {}) { return Graph(n, edges, directed_graph_tag{}, cap); } static Graph create_undirected_graph(const int n, const std::vector& edges, const std::vector& 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(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 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& cap = {}) const { std::vector 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 par; std::vector pre_ord, pst_ord; Graph tree, back; }; DFSTree dfs_tree(int start = 0) const { std::vector tree_edge, back_edge; std::vector pre(_n), pst(_n); auto pre_it = pre.begin(), pst_it = pst.begin(); std::vector eid(_n, -1), par(_n, -2); std::vector> 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 _adj; std::vector _edges; static std::vector make_edges(const std::vector>& g) { const int n = g.size(); std::vector 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 Graph(int, std::vector>, GraphTag, std::vector = {})->Graph; template Graph(int, std::vector>, GraphTag, std::vector = {})->Graph; Graph(std::vector>)->Graph; template Graph(std::vector>>)->Graph; template , std::nullptr_t> = nullptr> struct GraphBuilder { using graph_tag = GraphTag; using weight_type = WeightType; using edge_type = typename Graph::input_edge_type; GraphBuilder(int n = 0) : _n(n) {} void add_edge(const edge_type& edge) { check_not_moved(); _edges.push_back(edge); } template void emplace_edge(Args &&...args) { check_not_moved(); _edges.emplace_back(std::forward(args)...); } template , std::nullptr_t> = nullptr> void add_edges(const EdgeContainer& edges) { for (const auto& edge : edges) add_edge(edge); } template Graph build() { if constexpr (move_edges) { _moved = true; return Graph(_n, std::move(_edges), graph_tag{}); } else { return Graph(_n, _edges, graph_tag{}); } } Graph build_without_move() { return build(); } static Graph build(const int n, const std::vector& edges) { GraphBuilder builder(n); builder.add_edges(edges); return builder.build(); } private: int _n; std::vector _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 using DirectedGraphBuilder = GraphBuilder; template using UndirectedGraphBuilder = GraphBuilder; template >, std::nullptr_t> = nullptr> using WeightedGraph = Graph; using UnweightedGraph = Graph; template struct is_weighted_graph { static constexpr bool value = false; }; template struct is_weighted_graph> { static constexpr bool value = Graph::weighted; }; template constexpr bool is_weighted_graph_v = is_weighted_graph::value; template struct is_unweighted_graph { static constexpr bool value = false; }; template struct is_unweighted_graph> { static constexpr bool value = not Graph::weighted; }; template constexpr bool is_unweighted_graph_v = is_unweighted_graph::value; } // namespace suisen namespace suisen { namespace internal { template struct CentroidDecomposition : Graph { friend struct CentroidDecompositionUnweighted; template , std::nullptr_t>> friend struct CentroidDecompositionWeighted; using graph_type = Graph; using weight_type = WeightType; CentroidDecomposition(const graph_type& g) : graph_type(g), n(this->size()), cpar(n, -1), cdep(n, std::numeric_limits::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]; } auto collect_adj(int root, int u) { using iterator = typename Graph::adjacent_list::iterator; struct iter { iter(CentroidDecomposition* ptr, int root, int u) : _ptr(ptr), _dr(ptr->dct_depth(root)), _cur((*ptr)[u].begin()), _end((*ptr)[u].end()) { _succ(); } decltype(auto) operator*() { return *_cur; } iter& operator++() { ++_cur, _succ(); return *this; } bool operator!=(std::nullptr_t) { return _cur != _end; } auto begin() { return *this; } auto end() { return nullptr; } private: CentroidDecomposition* _ptr; int _dr; iterator _cur, _end; void _succ() { while (_cur != _end and _ptr->dct_depth(int(*_cur)) < _dr) ++_cur; } }; return iter{ this, root, u }; } private: int n; std::vector cpar; std::vector cdep; std::vector csiz; void build() { std::vector eid(n, 0); cpar[0] = -1, csiz[0] = n; std::deque> 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 { using base_type = internal::CentroidDecomposition; using base_type::base_type; std::vector>> collect(int root, int root_val = 0) const { std::vector>> res{ { { root, root_val } } }; for (int sub_root : (*this)[root]) if (this->cdep[sub_root] > this->cdep[root]) { res.emplace_back(); std::deque> 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 , std::nullptr_t> = nullptr> struct CentroidDecompositionWeighted : internal::CentroidDecomposition { using base_type = internal::CentroidDecomposition; using base_type::base_type; using weight_type = typename base_type::weight_type; template , std::nullptr_t> = nullptr> std::vector>> collect(int root, Op op, weight_type root_val) const { std::vector>> res{ { { root, root_val } } }; for (auto [sub_root, ew] : (*this)[root]) if (this->cdep[sub_root] > this->cdep[root]) { res.emplace_back(); std::deque> 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 , std::nullptr_t> = nullptr> using CentroidDecompositionWeighted = internal::CentroidDecompositionWeighted; } // namespace suisen namespace suisen { template class CoordinateCompressorBuilder { public: struct Compressor { public: static constexpr int absent = -1; // default constructor Compressor() : _xs(std::vector{}) {} // Construct from strictly sorted vector Compressor(const std::vector &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()); 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()); 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())) - 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())) - 1; } private: std::vector _xs; static bool is_strictly_sorted(const std::vector &v) { return std::adjacent_find(v.begin(), v.end(), std::greater_equal()) == v.end(); } }; CoordinateCompressorBuilder() : _xs(std::vector{}) {} explicit CoordinateCompressorBuilder(const std::vector &xs) : _xs(xs) {} explicit CoordinateCompressorBuilder(std::vector &&xs) : _xs(std::move(xs)) {} template > = 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 auto push(const Iterator &first, const Iterator &last) -> decltype(std::vector{}.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 auto push(const Iterable &iterable) -> decltype(std::vector{}.push_back(*iterable.begin()), void()) { push(iterable.begin(), iterable.end()); } // Add data. template void emplace(Args &&...args) { _xs.emplace_back(std::forward(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 &xs) { return CoordinateCompressorBuilder(xs).build(); } // Build compressor from vector. static auto build(std::vector &&xs) { return CoordinateCompressorBuilder(std::move(xs)).build(); } // Build compressor from generator. template > = nullptr> static auto build(const int n, Gen generator) { return CoordinateCompressorBuilder(n, generator).build(); } private: std::vector _xs; }; } // namespace suisen constexpr int INF = 1 << 30; void solve() { int n; read(n); vector a(n); read(a); UnweightedGraph g = [&] { std::vector> g(n); LOOP(n - 1) { int u, v; read(u, v); --u, --v; g[u].push_back(v); g[v].push_back(u); } return g; }(); vector comp_id(n); vector dep(n); CentroidDecompositionUnweighted cd(g); vector ans(n); for (int root = 0; root < n; ++root) { vector> vs; int c = 0; for (int subroot : cd.collect_adj(root, root)) { auto dfs = [&](auto dfs, int u, int p, int d) -> void { vs.emplace_back(a[u], u); comp_id[u] = c; dep[u] = d; for (int v : cd.collect_adj(root, u)) if (v != p) { dfs(dfs, v, u, d + 1); } }; dfs(dfs, subroot, root, 1); ++c; } vs.emplace_back(a[root], root); comp_id[root] = c; dep[root] = 0; array, 3> top; top.fill({ -INF, -1 }); auto update_max = [&](int dep, int cid) { top[2] = { dep, cid }; if (top[1][0] < top[2][0]) swap(top[1], top[2]); if (top[0][0] < top[1][0]) swap(top[0], top[1]); if (top[0][1] == top[1][1]) swap(top[1], top[2]); }; auto get_max_dep = [&](int cid) { return top[0][1] != cid ? top[0][0] : top[1][0]; }; sort(ALL(vs), greater<>()); const int siz = vs.size(); for (int l = 0; l < siz;) { int r = l; while (r < siz and vs[l].first == vs[r].first) { int v = vs[r++].second; update_max(dep[v], comp_id[v]); } while (l < r) { int v = vs[l++].second; ans[v] = max(ans[v], dep[v] + get_max_dep(comp_id[v])); } } } print(ans); } int main() { int test_case_num = 1; // read(test_case_num); LOOP(test_case_num) solve(); return 0; }