結果
問題 | No.2704 L to R Graph |
ユーザー | suisen |
提出日時 | 2024-03-29 23:59:32 |
言語 | C++17 (gcc 12.3.0 + boost 1.83.0) |
結果 |
WA
|
実行時間 | - |
コード長 | 33,051 bytes |
コンパイル時間 | 3,213 ms |
コンパイル使用メモリ | 241,784 KB |
実行使用メモリ | 21,204 KB |
最終ジャッジ日時 | 2024-09-30 17:11:23 |
合計ジャッジ時間 | 10,215 ms |
ジャッジサーバーID (参考情報) |
judge5 / judge1 |
(要ログイン)
テストケース
テストケース表示入力 | 結果 | 実行時間 実行使用メモリ |
---|---|---|
testcase_00 | AC | 2 ms
5,248 KB |
testcase_01 | AC | 1 ms
5,248 KB |
testcase_02 | AC | 2 ms
5,248 KB |
testcase_03 | AC | 2 ms
5,248 KB |
testcase_04 | AC | 2 ms
5,248 KB |
testcase_05 | AC | 2 ms
5,248 KB |
testcase_06 | AC | 2 ms
5,248 KB |
testcase_07 | AC | 1 ms
5,248 KB |
testcase_08 | AC | 67 ms
14,256 KB |
testcase_09 | AC | 66 ms
14,280 KB |
testcase_10 | AC | 67 ms
14,280 KB |
testcase_11 | AC | 433 ms
21,080 KB |
testcase_12 | AC | 356 ms
21,204 KB |
testcase_13 | WA | - |
testcase_14 | AC | 396 ms
21,076 KB |
testcase_15 | AC | 278 ms
21,076 KB |
testcase_16 | AC | 394 ms
20,952 KB |
testcase_17 | AC | 354 ms
21,080 KB |
testcase_18 | AC | 402 ms
21,080 KB |
testcase_19 | AC | 406 ms
20,952 KB |
testcase_20 | AC | 388 ms
21,080 KB |
testcase_21 | WA | - |
testcase_22 | WA | - |
testcase_23 | AC | 168 ms
21,076 KB |
testcase_24 | AC | 166 ms
20,952 KB |
testcase_25 | AC | 163 ms
21,080 KB |
testcase_26 | AC | 156 ms
21,076 KB |
testcase_27 | AC | 64 ms
16,520 KB |
testcase_28 | AC | 62 ms
16,524 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 <cassert> #include <cstdint> #include <optional> #include <tuple> #include <utility> #include <vector> namespace suisen { struct FunctionalGraph { struct Doubling; template <typename T, T(*)(T, T), T(*)()> struct DoublingSum; friend struct Doubling; template <typename T, T(*op)(T, T), T(*e)()> friend struct DoublingSum; FunctionalGraph() : FunctionalGraph(0) {} FunctionalGraph(int n) : _n(n), _nxt(n) {} FunctionalGraph(const std::vector<int>& nxt) : _n(nxt.size()), _nxt(nxt) {} const int& operator[](int u) const { return _nxt[u]; } int& operator[](int u) { return _nxt[u]; } struct Doubling { friend struct FunctionalGraph; int query(int u, long long d) const { for (int l = _log; l >= 0; --l) if ((d >> l) & 1) u = _nxt[l][u]; return u; } struct BinarySearchResult { int v; long long step; operator std::pair<int, long long>() const { return std::pair<int, long long>{ v, step }; } }; template <typename Pred> auto max_step(int u, Pred &&f) const { assert(f(u)); long long step = 0; for (int l = _log; l >= 0; --l) if (int nxt_u = _nxt[l][u]; f(nxt_u)) { u = nxt_u, step |= 1LL << l; } return BinarySearchResult{ u, step }; } template <typename Pred> std::optional<BinarySearchResult> step_until(int u, Pred &&f) const { if (f(u)) return BinarySearchResult { u, 0 }; auto [v, step] = max_step(u, [&](int v) { return not f(v); }); v = _nxt[0][v], ++step; if (not f(v)) return std::nullopt; return BinarySearchResult{ v, step }; } private: int _n, _log; std::vector<std::vector<int>> _nxt; Doubling(const std::vector<int>& nxt, long long max_step) : _n(nxt.size()), _log(floor_log2(max_step)), _nxt(_log + 1, std::vector<int>(_n)) { _nxt[0] = nxt; for (int i = 1; i <= _log; ++i) for (int j = 0; j < _n; ++j) { _nxt[i][j] = _nxt[i - 1][_nxt[i - 1][j]]; } } }; template <typename T, T(*op)(T, T), T(*e)()> struct DoublingSum : private Doubling { friend struct FunctionalGraph; struct Result { int v; T sum; operator std::pair<int, T>() const { return std::pair<int, T>{ v, sum }; } }; auto query(int u, long long d) const { T sum = e(); for (int l = _log; l >= 0; --l) if ((d >> l) & 1) sum = op(sum, _dat[l][std::exchange(u, _nxt[l][u])]); return Result{ u, sum }; } struct BinarySearchResult { int v; T sum; long long step; operator std::tuple<int, T, long long>() const { return std::tuple<int, T, long long>{ v, sum, step }; } }; template <typename Pred> auto max_step(int u, Pred &&f) const { assert(f(e())); long long step = 0; T sum = e(); for (int l = _log; l >= 0; --l) { if (T nxt_sum = op(sum, _dat[l][u]); f(nxt_sum)) { sum = std::move(nxt_sum), u = _nxt[l][u], step |= 1LL << l; } } return BinarySearchResult{ u, sum, step }; } template <typename Pred> std::optional<BinarySearchResult> step_until(int u, Pred &&f) const { if (f(e())) return BinarySearchResult { u, e(), 0 }; auto [v, sum, step] = max_step(u, [&](const T& v) { return not f(v); }); sum = op(sum, _dat[0][v]), v = _nxt[0][v], ++step; if (not f(sum)) return std::nullopt; return BinarySearchResult{ v, sum, step }; } private: std::vector<std::vector<T>> _dat; DoublingSum(const std::vector<int>& nxt, long long max_step, const std::vector<T>& dat) : Doubling(nxt, max_step), _dat(_log + 1, std::vector<T>(_n, e())) { _dat[0] = dat; for (int i = 1; i <= _log; ++i) for (int j = 0; j < _n; ++j) { _dat[i][j] = op(_dat[i - 1][j], _dat[i - 1][_nxt[i - 1][j]]); } } }; Doubling doubling(long long max_step) const { return Doubling(_nxt, max_step); } template <typename T, T(*op)(T, T), T(*e)()> DoublingSum<T, op, e> doubling(long long max_step, const std::vector<T>& dat) const { return DoublingSum<T, op, e>(_nxt, max_step, dat); } struct InfinitePath { int head_v; int head_len; int loop_v; int loop_len; InfinitePath() = default; InfinitePath(int head_v, int head_len, int loop_v, int loop_len) : head_v(head_v), head_len(head_len), loop_v(loop_v), loop_len(loop_len) {} }; std::vector<InfinitePath> infinite_paths() const { std::vector<InfinitePath> res(_n); std::vector<int> vis(_n, _n); std::vector<int> dep(_n, 0); int time = 0; auto dfs = [&](auto dfs, int u) -> int { vis[u] = time; int v = _nxt[u]; if (vis[v] == vis[u]) { // found cycle int loop_len = dep[u] - dep[v] + 1; res[u] = { u, 0, u, loop_len }; return loop_len - 1; } else if (vis[v] < vis[u]) { res[u] = { u, res[v].head_len + 1, res[v].loop_v, res[v].loop_len }; return 0; } else { dep[v] = dep[u] + 1; int c = dfs(dfs, v); if (c > 0) { // in cycle res[u] = { u, 0, u, res[v].loop_len }; return c - 1; } else { // out of cycle res[u] = { u, res[v].head_len + 1, res[v].loop_v, res[v].loop_len }; return 0; } } }; for (int i = 0; i < _n; ++i, ++time) if (vis[i] == _n) dfs(dfs, i); return res; } /** * Calculates k'th iterate: f(f(f(...f(i)))) for all 0 <= i < N in O(N) time. * Reference: https://noshi91.hatenablog.com/entry/2019/09/22/114149 */ std::vector<int> kth_iterate(const long long k) const { assert(k >= 0); std::vector<int> res(_n); std::vector<int> forest_roots; std::vector<std::vector<int>> forest(_n); std::vector<std::vector<std::pair<long long, int>>> qs(_n); for (const auto& path : infinite_paths()) { const int v = path.head_v; (path.head_len == 0 ? forest_roots : forest[_nxt[v]]).push_back(v); if (path.head_len >= k) continue; qs[path.loop_v].emplace_back(k - path.head_len, v); } std::vector<int> dfs_path(_n); auto dfs = [&](auto dfs, int u, int d) -> void { dfs_path[d] = u; if (d >= k) res[u] = dfs_path[d - k]; for (int v : forest[u]) dfs(dfs, v, d + 1); }; for (int root : forest_roots) dfs(dfs, root, 0); std::vector<int8_t> seen(_n, false); for (int root : forest_roots) { if (seen[root]) continue; std::vector<int> cycle{ root }; for (int v = _nxt[root]; v != root; v = _nxt[v]) cycle.push_back(v); const int len = cycle.size(); for (int i = 0; i < len; ++i) { const int s = cycle[i]; seen[s] = true; for (const auto& [rem, res_index] : qs[s]) { res[res_index] = cycle[(i + rem) % len]; } } } return res; } private: int _n; std::vector<int> _nxt; static int floor_log2(long long v) { int l = 0; while (1LL << (l + 1) <= v) ++l; return l; } }; } // namespace suisen namespace suisen { class HeavyLightDecomposition { public: template <typename Q> using is_point_update_query = std::is_invocable<Q, int>; template <typename Q> using is_range_update_query = std::is_invocable<Q, int, int>; template <typename Q, typename T> using is_point_get_query = std::is_same<std::invoke_result_t<Q, int>, T>; template <typename Q, typename T> using is_range_fold_query = std::is_same<std::invoke_result_t<Q, int, int>, T>; using Graph = std::vector<std::vector<int>>; HeavyLightDecomposition() = default; HeavyLightDecomposition(Graph &g) : n(g.size()), visit(n), leave(n), head(n), ord(n), siz(n), par(n, -1), dep(n, 0) { for (int i = 0; i < n; ++i) if (par[i] < 0) dfs(g, i, -1); int time = 0; for (int i = 0; i < n; ++i) if (par[i] < 0) hld(g, i, -1, time); } HeavyLightDecomposition(Graph &g, const std::vector<int> &roots) : n(g.size()), visit(n), leave(n), head(n), ord(n), siz(n), par(n, -1), dep(n, 0) { for (int i : roots) dfs(g, i, -1); int time = 0; for (int i : roots) hld(g, i, -1, time); } int size() const { return n; } int lca(int u, int v) const { for (;; v = par[head[v]]) { if (visit[u] > visit[v]) std::swap(u, v); if (head[u] == head[v]) return u; } } int la(int u, int k, int default_value = -1) const { if (k < 0) return default_value; while (u >= 0) { int h = head[u]; if (visit[u] - k >= visit[h]) return ord[visit[u] - k]; k -= visit[u] - visit[h] + 1; u = par[h]; } return default_value; } int jump(int u, int v, int d, int default_value = -1) const { if (d < 0) return default_value; const int w = lca(u, v); int uw = dep[u] - dep[w]; if (d <= uw) return la(u, d); int vw = dep[v] - dep[w]; return d <= uw + vw ? la(v, (uw + vw) - d) : default_value; } int dist(int u, int v) const { return dep[u] + dep[v] - 2 * dep[lca(u, v)]; } template <typename T, typename Q, typename F, constraints_t<is_range_fold_query<Q, T>, std::is_invocable_r<T, F, T, T>> = nullptr> T fold_path(int u, int v, T identity, F bin_op, Q fold_query, bool is_edge_query = false) const { T res = identity; for (;; v = par[head[v]]) { if (visit[u] > visit[v]) std::swap(u, v); if (head[u] == head[v]) break; res = bin_op(fold_query(visit[head[v]], visit[v] + 1), res); } return bin_op(fold_query(visit[u] + is_edge_query, visit[v] + 1), res); } template < typename T, typename Q1, typename Q2, typename F, constraints_t<is_range_fold_query<Q1, T>, is_range_fold_query<Q2, T>, std::is_invocable_r<T, F, T, T>> = nullptr > T fold_path_noncommutative(int u, int v, T identity, F bin_op, Q1 fold_query, Q2 fold_query_rev, bool is_edge_query = false) const { T res_u = identity, res_v = identity; // a := lca(u, v) // res = fold(u -> a) + fold(a -> v) while (head[u] != head[v]) { if (visit[u] < visit[v]) { // a -> v res_v = bin_op(fold_query(visit[head[v]], visit[v] + 1), res_v); v = par[head[v]]; } else { // u -> a res_u = bin_op(res_u, fold_query_rev(visit[head[u]], visit[u] + 1)); u = par[head[u]]; } } if (visit[u] < visit[v]) { // a = u res_v = bin_op(fold_query(visit[u] + is_edge_query, visit[v] + 1), res_v); } else { // a = v res_u = bin_op(res_u, fold_query_rev(visit[v] + is_edge_query, visit[u] + 1)); } return bin_op(res_u, res_v); } template <typename Q, constraints_t<is_range_update_query<Q>> = nullptr> void update_path(int u, int v, Q update_query, bool is_edge_query = false) const { for (;; v = par[head[v]]) { if (visit[u] > visit[v]) std::swap(u, v); if (head[u] == head[v]) break; update_query(visit[head[v]], visit[v] + 1); } update_query(visit[u] + is_edge_query, visit[v] + 1); } template <typename T, typename Q, constraints_t<is_range_fold_query<Q, T>> = nullptr> T fold_subtree(int u, Q fold_query, bool is_edge_query = false) const { return fold_query(visit[u] + is_edge_query, leave[u]); } template <typename Q, constraints_t<is_range_update_query<Q>> = nullptr> void update_subtree(int u, Q update_query, bool is_edge_query = false) const { update_query(visit[u] + is_edge_query, leave[u]); } template <typename T, typename Q, constraints_t<is_point_get_query<Q, T>> = nullptr> T get_point(int u, Q get_query) const { return get_query(visit[u]); } template <typename Q, constraints_t<is_point_update_query<Q>> = nullptr> void update_point(int u, Q update_query) const { update_query(visit[u]); } std::vector<int> inv_ids() const { std::vector<int> inv(n); for (int i = 0; i < n; ++i) inv[visit[i]] = i; return inv; } int get_visit_time(int u) const { return visit[u]; } int get_leave_time(int u) const { return leave[u]; } int get_head(int u) const { return head[u]; } int get_kth_visited(int k) const { return ord[k]; } int get_subtree_size(int u) const { return siz[u]; } int get_parent(int u) const { return par[u]; } int get_depth(int u) const { return dep[u]; } std::vector<int> get_roots() const { std::vector<int> res; for (int i = 0; i < n; ++i) if (par[i] < 0) res.push_back(i); return res; } private: int n; std::vector<int> visit, leave, head, ord, siz, par, dep; int dfs(Graph &g, int u, int p) { par[u] = p; siz[u] = 1; int max_size = 0; for (int &v : g[u]) { if (v == p) continue; dep[v] = dep[u] + 1; siz[u] += dfs(g, v, u); if (max_size < siz[v]) { max_size = siz[v]; std::swap(g[u].front(), v); } } return siz[u]; } void hld(Graph &g, int u, int p, int &time) { visit[u] = time, ord[time] = u, ++time; head[u] = p >= 0 and g[p].front() == u ? head[p] : u; for (int v : g[u]) { if (v != p) hld(g, v, u, time); } leave[u] = time; } }; } // namespace suisen #include <atcoder/dsu> #include <atcoder/math> void solve() { int n, L, R; read(n, L, R); vector<int> a(n); read(a); for (auto &e : a) --e; FunctionalGraph g(a); auto paths = g.infinite_paths(); atcoder::dsu uf(n); vector<int> ss; REP(i, n) { int j = a[i]; if (uf.same(i, j)) { ss.push_back(j); } else { uf.merge(i, j); } } vector<int> pos(n, -1); atcoder::dsu uf_cycle(n); set<pair<int, int>> ce; vector<int> cv; for (int s : ss) { int id = 0; for (int v = s;;) { pos[v] = id++; cv.push_back(v); ce.emplace(v, a[v]); uf_cycle.merge(v, a[v]); v = a[v]; if (v == s) break; } } vector<vector<int>> t(n); REP(i, n) { int j = a[i]; if (ce.count({ i, j })) { continue; } t[j].push_back(i); } vector<int> d(n); HeavyLightDecomposition hld(t, cv); for (int r : cv) { auto dfs = [&](auto dfs, int u) -> void { for (int v : t[u]) { d[v] = d[u] + 1; dfs(dfs, v); } }; dfs(dfs, r); } auto f = [&](int u, int v) -> pair<int, int> { if (paths[u].loop_v != paths[v].loop_v) { if (paths[v].loop_v != v) return { -1, -1 }; int x = paths[u].loop_v; if (not uf_cycle.same(x, v)) return { -1, -1 }; // u -> x // x -> v int a = d[u]; int px = pos[x]; int pv = pos[v]; int l = paths[x].loop_len; if (px <= pv) { a += pv - px; } else { a += pv - px + l; } return { a, l }; } int tu = hld.get_visit_time(u); int tvl = hld.get_visit_time(v); int tvr = hld.get_leave_time(v); if (tvl <= tu and tu < tvr) { return { d[u] - d[v], paths[v].loop_v != v ? iinf : paths[v].loop_len }; } return { -1, -1 }; }; int q; read(q); LOOP(q) { int s, t; read(s, t); --s, --t; auto [a, b] = f(s, t); if (a == -1) { print(-1); continue; } assert(a > 0 and b > 0); if (b == iinf) { // kL <= a <= kR int kl = fld(a, L), kr = cld(a, R); print(kr <= kl ? kr : -1); continue; } // xL <= A+yB <= xR int xmin = cld(a, R); long long ng = xmin - 1, ok = 1000000; while (ok - ng > 1) { long long x = (ok + ng) / 2; long long sumR = atcoder::floor_sum(x + 1, b, R, -a); long long sumL = atcoder::floor_sum(x + 1, b, L, -(a + 1)); (sumL < sumR ? ok : ng) = x; } print(ok == 1000000 ? -1 : ok); } } int main() { int test_case_num = 1; // read(test_case_num); LOOP(test_case_num) solve(); return 0; }