E - Permute K times

onlyblues發表於2024-08-18

E - Permute K times

Problem Statement

You are given a sequence $X$ of length $N$ where each element is between $1$ and $N$, inclusive, and a sequence $A$ of length $N$.
Print the result of performing the following operation $K$ times on $A$.

  • Replace $A$ with $B$ such that $B_i = A_{X_i}$.

Constraints

  • All input values are integers.
  • $1 \le N \le 2 \times 10^5$
  • $0 \le K \le 10^{18}$
  • $1 \le X_i \le N$
  • $1 \le A_i \le 2 \times 10^5$

Input

The input is given from Standard Input in the following format:

$N$ $K$
$X_1$ $X_2$ $\dots$ $X_N$
$A_1$ $A_2$ $\dots$ $A_N$

Output

Let $A'$ be the sequence $A$ after the operations. Print it in the following format:

$A'_1$ $A'_2$ $\dots$ $A'_N$


Sample Input 1

7 3
5 2 6 3 1 4 6
1 2 3 5 7 9 11

Sample Output 1

7 2 3 5 1 9 3

In this input, $X=(5,2,6,3,1,4,6)$ and the initial sequence is $A=(1,2,3,5,7,9,11)$.

  • After one operation, the sequence is $(7,2,9,3,1,5,9)$.
  • After two operations, the sequence is $(1,2,5,9,7,3,5)$.
  • After three operations, the sequence is $(7,2,3,5,1,9,3)$.

Sample Input 2

4 0
3 4 1 2
4 3 2 1

Sample Output 2

4 3 2 1

There may be cases where no operations are performed.


Sample Input 3

9 1000000000000000000
3 7 8 5 9 3 7 4 2
9 9 8 2 4 4 3 5 3

Sample Output 3

3 3 3 3 3 3 3 3 3

解題思路

  比賽時一直想著線性的做法,完全沒考慮過倍增,結果發現程式碼巨難寫。

  首先如果按照 $i \to x_i$ 進行連邊,就會得到一棵基環樹,當 $k$ 足夠大的時候其實就是在環上不斷迴圈。對於每個點可以先讓 $k$ 減去該點到環的距離,然後對環的大小取模,求出最後停留在環上的哪個位置,但實現起來非常複雜。本質上就是快速求出每個點在走 $k$ 步後最後停留在哪裡,由於 $k$ 非常大這啟發我們可以往倍增上考慮。

  定義 $X^{j}_{i}$ 表示從點 $i$ 經過 $2^j$ 步後到達的位置,$X^{0}_{i}$ 就是初始輸入的資料。想要求得 $X^{j}_{i}$,我們可以先讓 $i$ 走 $2^{j-1}$ 步到達 $X^{j-1}_{i}$,再從 $X^{j-1}_{i}$ 走 $2^{j-1}$ 步到達 $X^{j}_{i}$,因此有轉移方程 $X^{j}_{i} = X^{j-1}_{X^{j-1}_{i}}$。

  為了求出從 $i$ 走 $k$ 步的結果,先把 $k$ 看作二進位制數 $k_{59}k_{58} \cdots k_{0}, \, k_j \in \{0,1\}$,維護一個陣列 $p_i$ 表示從 $i$ 經過若干步後到達的位置,初始時定義 $p_i = i$。然後列舉 $k$ 的每一個二進位制位,如果 $k_j = 1$,意味著我們需要走 $2^{j}$ 步,更新 $p_i = X^{j}_{p_i}$。

  最後輸出 $a_{p_i}$ 即可。

  AC 程式碼如下,時間複雜度為 $O(n \log{k})$:

#include <bits/stdc++.h>
using namespace std;

typedef long long LL;

const int N = 2e5 + 5;

int x[60][N], p[N], a[N];

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int n;
    LL m;
    cin >> n >> m;
    for (int i = 1; i <= n; i++) {
        cin >> x[0][i];
    }
    for (int i = 1; 1ll << i <= m; i++) {
        for (int j = 1; j <= n; j++) {
            x[i][j] = x[i - 1][x[i - 1][j]];
        }
    }
    iota(p + 1, p + n + 1, 1);
    for (int i = 0; 1ll << i <= m; i++) {
        if (m >> i & 1) {
            for (int j = 1; j <= n; j++) {
                p[j] = x[i][p[j]];
            }
        }
    }
    for (int i = 1; i <= n; i++) {
        cin >> a[i];
    }
    for (int i = 1; i <= n; i++) {
        cout << a[p[i]] << ' ';
    }
    
    return 0;
}

參考資料

  Editorial - AtCoder Beginner Contest 367:https://atcoder.jp/contests/abc367/editorial/10707

相關文章