思路:i→xi 连边建图,找环,然后对于不在环上的点求出走到一个环上后走到的点和步数,然后根据环的周期缩小 k 到 O(n) 级别。
代码:
// Problem: E - Permute K times
// Contest: AtCoder - AtCoder Beginner Contest 367
// URL: https://atcoder.jp/contests/abc367/tasks/abc367_e
// Memory Limit: 1024 MB
// Time Limit: 2000 ms
// Good luck to the code >w<
//
// Powered by CP Editor (https://cpeditor.org)
#include<bits/stdc++.h>
using namespace std;
const int maxn = 2e5 + 5;
#define ll long long
vector<int> row[maxn], pth[maxn]; int rcnt, pcnt;
ll k; int n, a[maxn], x[maxn], idr[maxn], idp[maxn], d[maxn];
#define mk make_pair
bool vis[maxn], inr[maxn], imp[maxn];
int st[maxn], top, pp[maxn], pr[maxn], tor[maxn];
void dfs1(int u) {
if (inr[u]) return ;
if (vis[u]) {
int i; ++ rcnt;
for (i = top; st[i] != u; i --); int j = i;
for (; i <= top; i ++)
imp[st[i]] = 0, inr[st[i]] = 1, row[idr[st[i]] = rcnt].push_back(st[i]), pr[st[i]] = row[idr[st[i]]].size() - 1;
return top = j - 1, void(0);
}
if (imp[u]) return ;
vis[st[++ top] = u] = imp[u] = 1; dfs1(x[u]); vis[u] = 0;
}
bool inp[maxn];
int dfs2(int u) {
if (inr[u]) return u;
if (inp[u]) return tor[u];
pth[idp[u] = pcnt].push_back(u), pp[u] = pth[pcnt].size() - 1; inp[u] = 1;
return tor[u] = dfs2(x[u]);
}
int ans[maxn];
int main() {
scanf("%d %lld", &n, &k);
for (int i = 1; i <= n; i ++) scanf("%d", &x[i]), d[x[i]] ++;
for (int i = 1; i <= n; i ++) scanf("%d", &a[i]);
for (int i = 1; i <= n; i ++)
if (!imp[i]) top = 0, dfs1(i);
for (int i = 1; i <= n; i ++)
if (d[i] == 0) pcnt ++, dfs2(i);
for (int i = 1; i <= n; i ++) {
if (inr[i]) {
int R = idr[i], pos = pr[i], Length = row[R].size(), mov = k % Length;
ans[i] = a[row[R][(pos + mov) % Length]];
} else {
int P = idp[i], pos = pp[i], Length = pth[P].size();
if (Length - pos - 1 >= k) ans[i] = a[pth[P][pos + k]];
else {
int u = tor[i], R = idr[u], upos = pr[u], uLength = row[R].size(), mov = (k - Length) % uLength;
ans[i] = a[row[R][(upos + mov) % uLength]];
}
} printf("%d ", ans[i]);
}
return 0;
}