树状数组实现查找K小的元素


回顾树状数组的定义,注意到有如下两条性质:
一,c[ans]=sum of A[ans-lowbit(ans)+1 ... ans];
二,当ans=2^k时,
 c[ans]=sum of A[1 ... ans];

下面说明findK(k)如何运作:
1,设置边界条件ans,ans'<maxn且cnt<=k;
2,初始化cnt=c[ans],其中ans=2^k且k为满足边界条件的最大整数;
3,找到满足边界条件的最大的ans'使得ans'-lowbit(ans')=ans,即ans'满足c[ans']=A[ans+1 .. ans'](根据性质一),只要将c[ans']累加到cnt中(此时cnt=sum of A[1 ... ans'],根据性质二),cnt便可以作为k的逼近值;
4,重复第3步直到cnt已无法再逼近k,此时ans刚好比解小1,返回ans+1。

因此findk(k)的实质就是二分逼近

 

/* *********************************
树状数组实现查找K小的元素
                  经典。
限制:数据范围在1<<20 以内
**********************************
*/
#include 
< iostream >
using   namespace  std;

#define  maxn 1<<20
int  n,k;
int  c[maxn];

int  lowbit( int  x){
    
return  x &- x;
}

void  insert( int  x, int  t){
       
while (x < maxn){
          c[x]
+= t;
          x
+= lowbit(x);    
       }
}
int  find( int  k){
    
int  cnt = 0 ,ans = 0 ;
    
for ( int  i = 20 ;i >= 0 ;i -- ){
        ans
+= ( 1 << i);
        
if (ans >= maxn  ||  cnt + c[ans] >= k)ans -= ( 1 << i);
        
else  cnt += c[ans];
    }
    
return  ans + 1 ;
}
void  input(){
       memset(c,
0 , sizeof (c));
       
int  t;
       scanf(
" %d%d " , & n, & k);
       
for ( int  i = 0 ;i < n;i ++ ){    
            scanf(
" %d " , & t);
            insert(t,
1 );
       }
       printf(
" %d\n " ,find(k));
}
int  main(){
    
int  cases;
    scanf(
" %d " , & cases);
    
while (cases -- ){
        input();
    }
    
return   0 ;
}

转载于:https://www.cnblogs.com/zgmf_x20a/archive/2008/11/15/1334109.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值