有这么一则传闻,O(nlogn)的排序发明之前,滋滋国的排序都是采用的冒泡排序。即使是冒泡排序,对当时的国民
来说也太复杂太难以理解,于是滋滋国出现了这样一个职业——排序使,收取报酬并负责给序列排序。作为冒泡协
会首席排序使,Lyra收费颇高,为了照顾并不富裕的人,Lyra允许顾客只支付一部分酬劳并获得并不完美的冒泡排
序服务。众所周知,n个元素的冒泡排序需要n?1n-1轮才能完成,有一位顾客支付的费用,只能够完成前k轮的排序
。作为冒泡排序的首席排序使,天赋卓绝的Lyra暗地里早就掌握了O(nlogn)的排序方法,这也是她轻松当选首席排
序使的原因——排序速度无人能敌。而现在面对只能够完成前k轮冒泡排序的要求,Lyra犯了难,于是她来寻求你
的帮助。给定一个序列,执行如下程序:
for i from 1 to k
for j from 1 to n-1
if Aj>Aj+1
swap(Aj,Aj+1)
并输出之后的A序列。
#include <bits/stdc++.h>
using namespace std ;
#define N 200010
#define lowbit( i ) i&(-i)
int ans[ N ] , n , k , rk[ N ] , f[ N ] , c[ N ] ;
struct node {
int val , id ;
}a[ N ] ;
//每次冒泡排序都会把当前数前移一位(如果前面有比它大的数的话)
//用树状数组维护当前有几个比它大的
//如果比它大的超过k个那么直接前移k位就好了(k次都有比当前大的数,移动了k位)
//最后剩下的位置一位一位地去填,从小到大填
bool cmp( node a, node b ) {
return a.val < b.val ;
}
void add( int x , int val ) {
for( int i = x ; i <= n ; i += lowbit( i ) )
c[ i ] += val ;
}
int query( int x ) {
int ans = 0 ;
for( int i = x ; i ; i -= lowbit( i ) ) ans += c[ i ] ;
return ans ;
}
int main() {
scanf( "%d%d" , &n , &k ) ;
for( int i = 1 ; i <= n ; i ++ ) {
scanf( "%d" , &a[ i ].val ) ;
a[ i ].id = i ;
}
sort( a + 1 , a + n + 1 , cmp ) ;
rk[ a[ 1 ].id ] = 1 ;
for( int i = 2 ; i <= n ; i ++ ) {
if( a[ i ].val == a[ i - 1 ].val ) rk[ a[ i ].id ] = rk[ a[ i - 1 ].id ] ;
else rk[ a[ i ].id ] = i ;
}
for( int i = 1 ; i <= n ; i ++ ) {
add( rk[ i ] , 1 ) ;
f[ i ] = query( n ) - query( rk[ i ] ) ;
if( f[ i ] > k ) ans[ i - k ] = a[ rk[ i ] ].val ;
}
int cur = 1 ;
for( int i = 1 ; i <= n ; i ++ ) {
if( f[ a[ i ].id ] <= k ) {
while( cur <= n && ans[ cur ] ) cur ++ ;
ans[ cur ] = a[ i ].val ;
}
}
for( int i = 1 ; i <= n ; i ++ ) {
printf( "%d\n" ,ans[ i ] ) ;
}
return 0 ;
}