#include using namespace std; #include #include #include #include #include struct FastIO { FastIO() { std::ios_base::sync_with_stdio(false); std::cin.tie(nullptr); } }; inline FastIO fast_io_init; template std::istream& operator>>(std::istream& is, std::vector& v); template std::istream& operator>>(std::istream& is, std::pair& p) { return is >> p.first >> p.second; } template void read_tuple_impl(std::istream& is, Tuple& t, std::index_sequence) { (..., (is >> std::get(t))); } template std::istream& operator>>(std::istream& is, std::tuple& t) { read_tuple_impl(is, t, std::index_sequence_for{}); return is; } template std::istream& operator>>(std::istream& is, std::vector& v) { for (auto& elem : v) { is >> elem; } return is; } using default_type = long; template void read(Args&... args) { (std::cin >> ... >> args); } template T read_val() { T val; std::cin >> val; return val; } template std::pair read_pair() { std::pair p; std::cin >> p; return p; } template std::tuple read_tuple() { std::tuple t; std::cin >> t; return t; } template std::vector read_vec(int n) { std::vector v(n); std::cin >> v; return v; } template std::vector read_vec() { int n; std::cin >> n; return read_vec(n); } template std::vector> read_vec_pair(int n) { std::vector> v(n); std::cin >> v; return v; } template std::vector> read_vec_pair() { int n; std::cin >> n; return read_vec_pair(n); } template std::vector> read_vec_tuple(int n) { std::vector> v(n); std::cin >> v; return v; } template std::vector> read_vec_tuple() { int n; std::cin >> n; return read_vec_tuple(n); } template std::vector> read_vec_grid(int h, int w) { std::vector> grid(h, std::vector(w)); std::cin >> grid; return grid; } template std::vector> read_vec_grid() { int h, w; std::cin >> h >> w; return read_vec_grid(h, w); } template std::vector> read_vec_var(int n) { std::vector> res(n); for (int i = 0; i < n; ++i) { int m; std::cin >> m; res[i] = read_vec(m); } return res; } template std::vector> read_vec_var() { int n; std::cin >> n; return read_vec_var(n); } template T read_zero_idx() { T val; std::cin >> val; return val - 1; } inline std::vector> read_graph(int n, int m, bool directed = false) { std::vector> g(n); for (int i = 0; i < m; ++i) { int u = read_zero_idx(); int v = read_zero_idx(); g[u].push_back(v); if (!directed) { g[v].push_back(u); } } return g; } inline std::vector> read_graph(bool directed = false) { int n, m; std::cin >> n >> m; return read_graph(n, m, directed); } #include #include #include #include #define ALL(a) (a).begin(), (a).end() using i128 = __int128; template inline bool chmin(T& a, const U& b) { if (a > b) { a = b; return true; } return false; } template inline bool chmax(T& a, const U& b) { if (a < b) { a = b; return true; } return false; } template inline T div_ceil(T a, T b) { if (a > 0) return a / b + (a % b != 0); return a / b; } template inline T div_floor(T a, T b) { if (a < 0) return a / b - (a % b != 0); return a / b; } template inline T mod(T a, T m) { a %= m; if (a < 0) a += m; return a; } template inline constexpr T INF = std::numeric_limits::max() / 2; template <> inline constexpr float INF = std::numeric_limits::infinity(); template <> inline constexpr double INF = std::numeric_limits::infinity(); template <> inline constexpr long double INF = std::numeric_limits::infinity(); template inline std::vector iota_vec(int n, T start = 0) { std::vector v(n); std::iota(v.begin(), v.end(), start); return v; } template inline std::vector doubled_vec(const std::vector& v) { std::vector res; res.reserve(v.size() * 2); res.insert(res.end(), v.begin(), v.end()); res.insert(res.end(), v.begin(), v.end()); return res; } inline void Yes(bool b = true) { std::println("{}", (b ? "Yes" : "No")); } inline void No() { std::println("No"); } #ifdef LOCAL #include #else #define debug(...) #endif #include #include #include #include struct FunctionalGraph { int n; int log_k; std::vector to; std::vector cycle_id; std::vector cycle_pos; std::vector> cycles; std::vector root; std::vector depth; std::vector> doubling; std::vector> children; bool is_built = false; std::vector tree_pref; std::vector> cycle_pref; std::vector cycle_sum; bool has_weight = false; explicit FunctionalGraph(int n, const std::vector& to) : n(n), to(to), cycle_id(n, -1), cycle_pos(n, -1), root(n, -1), depth(n, 0) { log_k = std::max(1, std::bit_width(static_cast(n))); } void build() { std::vector state(n, 0); std::vector path; for (int i = 0; i < n; i++) { if (state[i] != 0) continue; int curr = i; path.clear(); while (state[curr] == 0) { state[curr] = 1; path.push_back(curr); curr = to[curr]; } if (state[curr] == 1) { std::vector cycle; bool in_cycle = false; for (int v : path) { if (v == curr) in_cycle = true; if (in_cycle) { cycle_id[v] = cycles.size(); cycle_pos[v] = cycle.size(); root[v] = v; depth[v] = 0; cycle.push_back(v); } } cycles.push_back(cycle); } for (int j = static_cast(path.size()) - 1; j >= 0; j--) { int u = path[j]; state[u] = 2; if (root[u] == -1) { int next_v = to[u]; root[u] = root[next_v]; depth[u] = depth[next_v] + 1; } } } children.assign(n, {}); for (int i = 0; i < n; i++) { if (cycle_id[i] == -1) { children[to[i]].push_back(i); } } doubling.assign(log_k, std::vector(n)); for (int i = 0; i < n; i++) doubling[0][i] = to[i]; for (int k = 0; k < log_k - 1; k++) { for (int i = 0; i < n; i++) { doubling[k + 1][i] = doubling[k][doubling[k][i]]; } } is_built = true; } template void build_weight(const std::vector& weight) { assert(is_built && "You must call build() before calling build_weight()."); assert(static_cast(weight.size()) == n); tree_pref.assign(n, 0); int num_cycles = cycles.size(); cycle_pref.assign(num_cycles, {}); cycle_sum.assign(num_cycles, 0); for (int cid = 0; cid < num_cycles; cid++) { for (int r : cycles[cid]) { tree_pref[r] = 0; std::vector q = {r}; int head = 0; while (head < static_cast(q.size())) { int p = q[head++]; for (int c : children[p]) { tree_pref[c] = tree_pref[p] + static_cast(weight[c]); q.push_back(c); } } } } for (int cid = 0; cid < num_cycles; cid++) { int sz = cycles[cid].size(); cycle_pref[cid].assign(sz + 1, 0); for (int i = 0; i < sz; i++) { int v = cycles[cid][i]; cycle_pref[cid][i + 1] = cycle_pref[cid][i] + static_cast(weight[v]); cycle_sum[cid] += static_cast(weight[v]); } } has_weight = true; } int jump(int u, long long k) const { assert(is_built && "You must call build() before using jump()."); if (k <= depth[u]) { for (int i = 0; k > 0; i++, k >>= 1) { if (k & 1) u = doubling[i][u]; } return u; } k -= depth[u]; int r = root[u]; int cid = cycle_id[r]; int c_size = cycles[cid].size(); return cycles[cid][(cycle_pos[r] + k) % c_size]; } long long path_sum(int u, long long k) const { assert(has_weight && "build_weight must be called before evaluating path_sum"); if (k <= 0) return 0; long long ans = 0; if (k <= depth[u]) { int v = jump(u, k); ans = tree_pref[u] - tree_pref[v]; } else { ans += tree_pref[u]; k -= depth[u]; int r = root[u]; int cid = cycle_id[r]; long long sz = cycles[cid].size(); long long loops = k / sz; ans += loops * cycle_sum[cid]; int rem = k % sz; if (rem > 0) { int start_idx = cycle_pos[r]; if (start_idx + rem <= sz) { ans += cycle_pref[cid][start_idx + rem] - cycle_pref[cid][start_idx]; } else { ans += cycle_pref[cid][sz] - cycle_pref[cid][start_idx]; ans += cycle_pref[cid][(start_idx + rem) % sz]; } } } return ans; } long long dist(int u, int v) const { assert(is_built && "You must call build() before using dist()."); if (root[u] != root[v]) { if (cycle_id[root[u]] != cycle_id[root[v]]) return -1; if (cycle_id[v] == -1) return -1; } if (cycle_id[v] == -1) { if (depth[u] < depth[v]) return -1; int diff = depth[u] - depth[v]; if (jump(u, diff) == v) return diff; return -1; } else { long long d = depth[u]; int r_u = root[u]; int c_size = get_cycle_size(r_u); int diff_cycle = (cycle_pos[v] - cycle_pos[r_u] + c_size) % c_size; return d + diff_cycle; } } int get_cycle_size(int u) const { assert(is_built && "You must call build() before using get_cycle_size()."); return cycles[cycle_id[root[u]]].size(); } bool on_cycle(int u) const { assert(is_built && "You must call build() before using on_cycle()."); return cycle_id[u] != -1; } int dist_to_cycle(int u) const { assert(is_built && "You must call build() before using dist_to_cycle()."); return depth[u]; } }; void solve() { ios::sync_with_stdio(false); cin.tie(nullptr); int N; read(N); auto A = read_vec(N); for (auto& a : A) a--; FunctionalGraph fg(N, A); fg.build(); auto vec = fg.cycle_id; debug(vec); int mx = *ranges::max_element(vec); println("{}", mx + 1); } int main() { solve(); }