题目描述 https://codeforces.com/contest/1619/problem/H
简要题意:给定一个长度为 $n$ 的排列 $p_i$,现在有 $m$ 次操作,操作有两种,第一种给定 $x$ 和 $y$,交换 $p_x$ 和 $p_y$,第二种给定 $i$ 和 $k$,求执行 $i=p_i$操作 $k$ 次之后,$i$ 的值
$n,m,k\le 10^5$
Solution 考虑根号分治,我们对于每个点维护跳 $O(\sqrt n)$ 次到达的位置,这样在交换 $p_x$ 和 $p_y$ 时候,需要修改的点只有 $O(\sqrt n)$ 个,查询我们也只需要跳 $O(\sqrt n)$ 步
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 #include <iostream> #include <cmath> #include <vector> #define maxn 100010 using namespace std ;int n, m, B, p[maxn], q[maxn], nxt[maxn];void solve (int x) { int u = x, v = p[x]; for (int i = 1 ; i < B; ++i) u = q[u]; for (int i = 1 ; i < B; ++i) { nxt[u] = v; u = p[u]; v = p[v]; } } inline void solve_1 () { int x, y; cin >> x >> y; swap(q[p[x]], q[p[y]]); swap(p[x], p[y]); swap(nxt[x], nxt[y]); solve(x); solve(y); } inline void solve_2 () { int x, y; cin >> x >> y; while (y >= B) x = nxt[x], y -= B; for (int i = 1 ; i <= y; ++i) x = p[x]; cout << x << "\n" ; } int main () { ios::sync_with_stdio(false ); cin .tie(nullptr ); cout .tie(nullptr ); cin >> n >> m; B = sqrt (n); for (int i = 1 ; i <= n; ++i) cin >> p[i], q[p[i]] = i; for (int i = 1 ; i <= n; ++i) { int x = i; for (int j = 1 ; j <= B; ++j) x = p[x]; nxt[i] = x; } for (int i = 1 ; i <= m; ++i) { int opt; cin >> opt; if (opt == 1 ) solve_1(); else solve_2(); } return 0 ; }