E. Permutation Sorting
You are given a permutation$^\dagger$ $a$ of size $n$. We call an index $i$ good if $a_i=i$ is satisfied. After each second, we rotate all indices that are not good to the right by one position. Formally,
- Let $s_1,s_2,\ldots,s_k$ be the indices of $a$ that are not good in increasing order. That is, $s_j < s_{j+1}$ and if index $i$ is not good, then there exists $j$ such that $s_j=i$.
- For each $i$ from $1$ to $k$, we assign $a_{s_{(i \% k+1)}} := a_{s_i}$ all at once.
For each $i$ from $1$ to $n$, find the first time that index $i$ becomes good.
$^\dagger$ A permutation is an array consisting of $n$ distinct integers from $1$ to $n$ in arbitrary order. For example, $[2,3,1,5,4]$ is a permutation, but $[1,2,2]$ is not a permutation ($2$ appears twice in the array) and $[1,3,4]$ is also not a permutation ($n=3$ but there is $4$ in the array).
Input
Each test contains multiple test cases. The first line contains the number of test cases $t$ ($1 \le t \le 10^4$). The description of the test cases follows.
The first line of each test case contains a single integer $n$ ($1 \le n \le 10^6$) — the size of permutation $a$.
The second line of each test case contains $n$ integers $a_1, a_2, \ldots, a_n$ ($1 \le a_i \le n$) — the elements of permutation $a$.
It is guaranteed that the sum of $n$ over all test cases does not exceed $10^6$.
Output
For each test case, output a single line containing $n$ integers where the $i$-th integer represents the first time that index $i$ becomes good.
Example
input
2
5
3 2 4 1 5
6
2 1 4 6 5 3
output
1 0 1 1 0
2 1 2 1 0 1
Note
In the first test case, $2$ and $5$ are already in the correct position so indices $2$ and $5$ become good at $0$ second. After $1$ second, a cyclic shift will be done with $s=[1, 3, 4]$, resulting in array $a=[1, 2, 3, 4, 5]$. Notice that indices $1$, $3$ and $4$ become good at $1$ second.
In the second test case, $5$ is already in the correct position, so index $5$ becomes good at $0$ second. After $1$ second, a cyclic shift will be done with $s=[1, 2, 3, 4, 6]$, resulting in array $a=[3, 2, 1, 4, 5, 6]$. Notice that indices $2$, $4$ and $6$ become good at $1$ second. After $2$ seconds, a cyclic shift will be done with $s=[1, 3]$, resulting in array $a=[1, 2, 3, 4, 5, 6]$. Notice that indices $1$ and $3$ become good at $2$ second.
解题思路
为了方便将数组 $a$ 的每个元素减 $1$。定义 $h_i$ 表示将元素 $a_i$ 从下标 $i$ 移到下标 $a_i$ 所需要的时间,有 $h_i = (a_i - i) \bmod n$。同时破环成链,把数组 $h$ 拷贝一份接到后面,即对于 $i \in [n, 2n - 1]$,有 $h_i = h_{i - n}$。
考虑计算下标为 $a_i$ 的答案,首先需要将 $a_i$ 向右移动 $h_i$ 个时间,假设在这个过程中存在元素 $a_j,$ 满足 $j \in [i+1, i+h_i]$ 且 $j + h_j \in [i + 1, i + h_i]$,即在 $a_i$ 移动的过程中这些元素移动到其对应的下标,那么 $a_i$ 就要跳过这些元素。假设有 $c$ 个这样的元素,那么实际上 $a_i$ 只用移动 $h_i - c$ 个时间。
因此对于每个 $a_i$,只需统计出有多少个元素 $a_j$ 满足 $\displaylines{\begin{cases} i+1 \leq j \leq i+h_i \\ i+1 \leq j+h_j \leq i+h_i \end{cases}}$。可以看作是一个二维数点问题,对于每个下标 $j \in [0,n-1]$,将 $(j, h_j)$ 看作是一个点,那么就相当于询问左下角为 $(i+1, i+1)$ 右上角为 $(i+h_i, i+h_i)$ 的矩形内有多少点。
AC 代码如下,时间复杂度为 $O(n \log{n})$:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 1e6 + 10, M = N * 2;
int n;
int a[N], h[M];
int tr[M];
struct Node {
int x, y, c, idx;
}p[N * 4];
int ans[N];
int lowbit(int x) {
return x & -x;
}
void add(int x, int c) {
for (int i = x; i <= n << 1; i += lowbit(i)) {
tr[i] += c;
}
}
int query(int x) {
int ret = 0;
for (int i = x; i; i -= lowbit(i)) {
ret += tr[i];
}
return ret;
}
void solve() {
scanf("%d", &n);
for (int i = 0; i < n; i++) {
scanf("%d", a + i);
a[i]--;
h[i] = h[i + n] = (a[i] - i + n) % n;
}
for (int i = 0, j = 0; i < n; i++) {
int x1 = i + 1, y1 = i + 1, x2 = i + h[i], y2 = i + h[i];
p[j++] = {x2, y2, 1, i};
p[j++] = {x1 - 1, y1 - 1, 1, i};
p[j++] = {x1 - 1, y2, -1, i};
p[j++] = {x2, y1 - 1, -1, i};
}
sort(p, p + n * 4, [&](Node &a, Node &b) {
return a.x < b.x;
});
for (int i = 0; i < n; i++) {
ans[a[i] % n] = h[i];
}
memset(tr, 0, n + 10 << 3);
for (int i = 0, j = 0; i < n << 2; i++) {
while (j < n << 1 && j <= p[i].x) {
add(j + h[j] + 1, 1); // 由于j+h[j]可能为0,因此加一个偏移量
j++;
}
ans[a[p[i].idx] % n] -= p[i].c * query(p[i].y + 1); // 同理加一个偏移量
}
for (int i = 0; i < n; i++) {
printf("%d ", ans[i]);
}
printf("\n");
}
int main() {
int t;
scanf("%d", &t);
while (t--) {
solve();
}
return 0;
}
参考资料
CodeTON Round 7 (Div. 1 + Div. 2, Rated, Prizes!) Editorial:https://codeforces.com/blog/entry/122172
标签:good,int,permutation,le,second,Sorting,Permutation,test From: https://www.cnblogs.com/onlyblues/p/17870634.html