E. Permutation Sorting

E. Permutation Sorting

You are given a permutation a of size n. We call an index i good if ai=i is satisfied. After each second, we rotate all indices that are not good to the right by one position. Formally,

  • Let s1,s2,,sk be the indices of a that are not good in increasing order. That is, sj<sj+1 and if index i is not good, then there exists j such that sj=i.
  • For each i from 1 to k, we assign as(i%k+1):=asi all at once.

For each i from 1 to n, find the first time that index i becomes good.

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 (1t104). The description of the test cases follows.

The first line of each test case contains a single integer n (1n106) — the size of permutation a.

The second line of each test case contains n integers a1,a2,,an (1ain) — the elements of permutation a.

It is guaranteed that the sum of n over all test cases does not exceed 106.

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。定义 hi 表示将元素 ai 从下标 i 移到下标 ai 所需要的时间,有 hi=(aii)modn。同时破环成链,把数组 h 拷贝一份接到后面,即对于 i[n,2n1],有 hi=hin

  考虑计算下标为 ai 的答案,首先需要将 ai 向右移动 hi 个时间,假设在这个过程中存在元素 aj, 满足 j[i+1,i+hi]j+hj[i+1,i+hi],即在 ai 移动的过程中这些元素移动到其对应的下标,那么 ai 就要跳过这些元素。假设有 c 个这样的元素,那么实际上 ai 只用移动 hic 个时间。

  因此对于每个 ai,只需统计出有多少个元素 aj 满足 {i+1ji+hii+1j+hji+hi。可以看作是一个二维数点问题,对于每个下标 j[0,n1],将 (j,hj) 看作是一个点,那么就相当于询问左下角为 (i+1,i+1) 右上角为 (i+hi,i+hi) 的矩形内有多少点。

  AC 代码如下,时间复杂度为 O(nlogn)

#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

posted @   onlyblues  阅读(11)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效
Web Analytics
点击右上角即可分享
微信分享提示