树状数组

树状数组 ——神奇而小巧的数据结构 

树状数组同样可以在O(logN)的时间复杂度下完美的解决引例中的所有操作,同样我们只需要一个一维数组tree[]。其中tree[i]表示[i-(i&(-i))+1,i]这个区间的 和(戒者最大值,以下只讨论和)。其 中i&(-i)表示i的二进制表示中最末一个1 的权值。例如tree[12]表示的是 [1001,1100]这一段的和 

若sum(i)表示[1,i]这个区间的和。则, sum(15)=tree[15]+tree[14]+tree[12]+ tree[8]。 

注意:树状数组的下标必须从1开始! 


Step 1:初始化。 

memset(tree,0,sizeof(tree)); 

Step 2:将下标为k的数加上val。 
void update(int k,int val) {  
    while (k<=N)  {   
        tree[k]+=val;   
        k+=k&(-k); 
    } 
} 
Step 3:查询区间[1,k]的和。 
int query(int k) {  
    int sum=0;  
    while (k>0)  {   
        sum+=tree[k];   
        k-=k&(-k);  
    }  
    return sum; 
} 

       如果要询问区间[l,r]的和,那么答案就是query(r)-query(l-1)。 


特殊应用:找整个数列的第K小数(即K=1时找最小值) 
int find_Kth(int k,int N) {  
    int now=0;  
    for (int i=20;i>=0;i--)  {   
        now|=(1<<i);   
        if (now>N || tree[now]>=k)    
            now^=(1<<i);   
        else k-=tree[now];  
    }  
    return now+1; 
} 


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值