Permutation Sorting (Codeforces 1896E)
Tags: Others, sortings

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.

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.

Sample Inputs:
2
5
3 2 4 1 5
6
2 1 4 6 5 3

Sample Outputs:
1 0 1 1 0 
2 1 2 1 0 1

Solution (Python):
import sys
input = sys.stdin.buffer.readline

def update(pos, v):
    while pos < len(T):
        T[pos] += v
        pos |= pos + 1

def _query(pos):
    r = 0
    while pos:
        r += T[pos - 1]
        pos &= pos - 1
    return r

def query(a, b):
    return _query(b) - _query(a)
for _ in range(int(input())):
    n = int(input())
    a = [0] + list(map(int, input().split()))
    rng = []
    T = [0] * 2 * (n + 1)
    for i in range(1, n + 1):
        if i <= a[i]:
            rng.append((i, a[i]))
            update(a[i] + n, 1)
        else:
            rng.append((i, a[i] + n))
    rng.sort(reverse=True)
    ans = [None] * n
    for (i, ai) in rng:
        ans[a[i] - 1] = ai - i - query(i + 1, ai)
        update(ai, 1)
    print(*ans)

Solution (Python):
class SortedList:

    def __init__(self, iterable=[], _load=200):
        """"""
        values = sorted(iterable)
        self._len = _len = len(values)
        self._load = _load
        self._lists = _lists = [values[i:i + _load] for i in range(0, _len, _load)]
        self._list_lens = [len(_list) for _list in _lists]
        self._mins = [_list[0] for _list in _lists]
        self._fen_tree = []
        self._rebuild = True

    def _fen_build(self):
        """"""
        self._fen_tree[:] = self._list_lens
        _fen_tree = self._fen_tree
        for i in range(len(_fen_tree)):
            if i | i + 1 < len(_fen_tree):
                _fen_tree[i | i + 1] += _fen_tree[i]
        self._rebuild = False

    def _fen_update(self, index, value):
        """"""
        if not self._rebuild:
            _fen_tree = self._fen_tree
            while index < len(_fen_tree):
                _fen_tree[index] += value
                index |= index + 1

    def _fen_query(self, end):
        """"""
        if self._rebuild:
            self._fen_build()
        _fen_tree = self._fen_tree
        x = 0
        while end:
            x += _fen_tree[end - 1]
            end &= end - 1
        return x

    def _fen_findkth(self, k):
        """"""
        _list_lens = self._list_lens
        if k < _list_lens[0]:
            return (0, k)
        if k >= self._len - _list_lens[-1]:
            return (len(_list_lens) - 1, k + _list_lens[-1] - self._len)
        if self._rebuild:
            self._fen_build()
        _fen_tree = self._fen_tree
        idx = -1
        for d in reversed(range(len(_fen_tree).bit_length())):
            right_idx = idx + (1 << d)
            if right_idx < len(_fen_tree) and k >= _fen_tree[right_idx]:
                idx = right_idx
                k -= _fen_tree[idx]
        return (idx + 1, k)

    def _delete(self, pos, idx):
        """"""
        _lists = self._lists
        _mins = self._mins
        _list_lens = self._list_lens
        self._len -= 1
        self._fen_update(pos, -1)
        del _lists[pos][idx]
        _list_lens[pos] -= 1
        if _list_lens[pos]:
            _mins[pos] = _lists[pos][0]
        else:
            del _lists[pos]
            del _list_lens[pos]
            del _mins[pos]
            self._rebuild = True

    def _loc_left(self, value):
        """"""
        if not self._len:
            return (0, 0)
        _lists = self._lists
        _mins = self._mins
        (lo, pos) = (-1, len(_lists) - 1)
        while lo + 1 < pos:
            mi = lo + pos >> 1
            if value <= _mins[mi]:
                pos = mi
            else:
                lo = mi
        if pos and value <= _lists[pos - 1][-1]:
            pos -= 1
        _list = _lists[pos]
        (lo, idx) = (-1, len(_list))
        while lo + 1 < idx:
            mi = lo + idx >> 1
            if value <= _list[mi]:
                idx = mi
            else:
                lo = mi
        return (pos, idx)

    def _loc_right(self, value):
        """"""
        if not self._len:
            return (0, 0)
        _lists = self._lists
        _mins = self._mins
        (pos, hi) = (0, len(_lists))
        while pos + 1 < hi:
            mi = pos + hi >> 1
            if value < _mins[mi]:
                hi = mi
            else:
                pos = mi
        _list = _lists[pos]
        (lo, idx) = (-1, len(_list))
        while lo + 1 < idx:
            mi = lo + idx >> 1
            if value < _list[mi]:
                idx = mi
            else:
                lo = mi
        return (pos, idx)

    def add(self, value):
        """"""
        _load = self._load
        _lists = self._lists
        _mins = self._mins
        _list_lens = self._list_lens
        self._len += 1
        if _lists:
            (pos, idx) = self._loc_right(value)
            self._fen_update(pos, 1)
            _list = _lists[pos]
            _list.insert(idx, value)
            _list_lens[pos] += 1
            _mins[pos] = _list[0]
            if _load + _load < len(_list):
                _lists.insert(pos + 1, _list[_load:])
                _list_lens.insert(pos + 1, len(_list) - _load)
                _mins.insert(pos + 1, _list[_load])
                _list_lens[pos] = _load
                del _list[_load:]
                self._rebuild = True
        else:
            _lists.append([value])
            _mins.append(value)
            _list_lens.append(1)
            self._rebuild = True

    def discard(self, value):
        """"""
        _lists = self._lists
        if _lists:
            (pos, idx) = self._loc_right(value)
            if idx and _lists[pos][idx - 1] == value:
                self._delete(pos, idx - 1)

    def remove(self, value):
        """"""
        _len = self._len
        self.discard(value)
        if _len == self._len:
            raise ValueError('{0!r} not in list'.format(value))

    def pop(self, index=-1):
        """"""
        (pos, idx) = self._fen_findkth(self._len + index if index < 0 else index)
        value = self._lists[pos][idx]
        self._delete(pos, idx)
        return value

    def bisect_left(self, value):
        """"""
        (pos, idx) = self._loc_left(value)
        return self._fen_query(pos) + idx

    def bisect_right(self, value):
        """"""
        (pos, idx) = self._loc_right(value)
        return self._fen_query(pos) + idx

    def count(self, value):
        """"""
        return self.bisect_right(value) - self.bisect_left(value)

    def __len__(self):
        """"""
        return self._len

    def __getitem__(self, index):
        """"""
        (pos, idx) = self._fen_findkth(self._len + index if index < 0 else index)
        return self._lists[pos][idx]

    def __delitem__(self, index):
        """"""
        (pos, idx) = self._fen_findkth(self._len + index if index < 0 else index)
        self._delete(pos, idx)

    def __contains__(self, value):
        """"""
        _lists = self._lists
        if _lists:
            (pos, idx) = self._loc_left(value)
            return idx < len(_lists[pos]) and _lists[pos][idx] == value
        return False

    def __iter__(self):
        """"""
        return (value for _list in self._lists for value in _list)

    def __reversed__(self):
        """"""
        return (value for _list in reversed(self._lists) for value in reversed(_list))

    def __repr__(self):
        """"""
        return 'SortedList({0})'.format(list(self))

class OrderedList(SortedList):

    def __init__(self, arg):
        super().__init__(arg)

    def rangeCountByValue(self, leftVal, rightVal):
        leftCummulative = self.bisect_left(leftVal)
        rightCummulative = self.bisect_left(rightVal + 1)
        return rightCummulative - leftCummulative

def main():
    t = int(input())
    allans = []
    for _ in range(t):
        ''
        n = int(input())
        a = readIntArr()
        for i in range(n):
            a[i] -= 1
        b = [-1] * (2 * n)
        for i in range(n):
            if a[i] >= i:
                b[a[i]] = i
                b[a[i] + n] = i + n
            else:
                b[a[i] + n] = i
        ans = [-1] * n
        sl = SortedList()
        for ai in range(2 * n):
            if b[ai] != -1:
                i = b[ai]
                ans[ai % n] = ai - i - (len(sl) - sl.bisect_left(i))
                sl.add(i)
        allans.append(ans)
    multiLineArrayOfArraysPrint(allans)
    return
import sys
input = sys.stdin.buffer.readline

def oneLineArrayPrint(arr):
    print(' '.join([str(x) for x in arr]))

def multiLineArrayPrint(arr):
    print('\n'.join([str(x) for x in arr]))

def multiLineArrayOfArraysPrint(arr):
    print('\n'.join([' '.join([str(x) for x in y]) for y in arr]))

def readIntArr():
    return [int(x) for x in input().split()]

def makeArr(defaultValFactory, dimensionArr):
    dv = defaultValFactory
    da = dimensionArr
    if len(da) == 1:
        return [dv() for _ in range(da[0])]
    else:
        return [makeArr(dv, da[1:]) for _ in range(da[0])]

def queryInteractive(a, b, c):
    print('? {} {} {}'.format(a, b, c))
    sys.stdout.flush()
    return int(input())

def answerInteractive(x1, x2):
    print('! {} {}'.format(x1, x2))
    sys.stdout.flush()
inf = float('inf')
from math import gcd, floor, ceil
import math
for _abc in range(1):
    main()

Solution (Python):
import io, os
input = io.BytesIO(os.read(0, os.fstat(0).st_size)).readline

class fenwick(object):

    def __init__(self, n):
        self.n = n
        self.cul = [0] * n
        self.maxd = len(bin(n)) - 3

    def update(self, index, diff):
        i = index
        while i < self.n:
            self.cul[i] += diff
            i += i + 1 & -i - 1

    def getaccu(self, index):
        output = 0
        i = index
        while i >= 0:
            output += self.cul[i]
            i -= i + 1 & -i - 1
        return output

    def search(self, target):
        accunum = 0
        accuindex = 0
        for i in range(self.maxd, -1, -1):
            d = 1 << i
            if accuindex + d > self.n:
                continue
            if accunum + self.cul[accuindex + d - 1] <= target:
                accunum += self.cul[accuindex + d - 1]
                accuindex += d
        return accuindex

def main(t):
    n = int(input())
    arr = list(map(int, input().split()))
    seg = []
    for i in range(n):
        arr[i] -= 1
    for i in range(n):
        if i <= arr[i]:
            seg.append((i, arr[i], arr[i]))
            seg.append((i + n, arr[i] + n, arr[i]))
        else:
            seg.append((i, arr[i] + n, arr[i]))
    fen = fenwick(2 * n)
    ans = [-1] * n
    seg.sort()
    for (start, end, index) in seg[::-1]:
        ans[index] = end - start - fen.getaccu(end) + fen.getaccu(start)
        fen.update(end, 1)
    print(*ans)
T = int(input())
t = 1
while t <= T:
    main(t)
    t += 1