浏览器标题切换
浏览器标题切换end
把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

BZOJ5170: Fable 树状数组

Description

有这么一则传闻,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序列。

Input

第一行两个整数n,k表示序列的长度和轮数。
接下来n行每行一个整数表示Ai
1≤k<n≤200000;1≤Ai≤10^9

Output

输出n行每行一个整数表示冒泡排序k轮后的Ai

Sample Input

3 1
3
2
1

Sample Output

2
1
3

Solution

我把冒泡的本质想错了...然后就一直写挂样例都过不了

看了zz的题解才发现自己错的好离谱...(orzz)

事实上每次冒泡排序都会把当前数前移一位(如果前面有比它大的数的话) 

用树状数组维护当前有几个比它大的

如果比它大的超过$k$个那么直接前移$k$位就好了($k$次都有比当前大的数,移动了$k$位)

最后剩下的位置一位一位地去填,从小到大填

我怎么觉得这题主要难度在于看懂冒泡排序到底怎么做的...(

#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 ;
} 

 

posted @ 2018-10-10 19:34  henry_y  阅读(284)  评论(0编辑  收藏  举报