ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

树状数组

2022-03-01 07:31:06  阅读:131  来源: 互联网

标签:树状 int 差分 区间 数组 序列


前言
树状数组,又称二叉索引树,是一种代码简单,应用广泛的神奇数据结构!
普通树状数组
概念普及:树状数组的原理


设黑色框内数组为A[1]→A[8]
那么可以得到以下式子:
C[1] = A[1];
C[2] = A[1] + A[2];;
C[3] = A[3];
C[4] = A[1] + A[2] + A[3] + A[4];
C[5] = A[5];
C[6] = A[5] + A[6];
C[7] = A[7];C[7]=A[7];
C[8]=A[1]+A[2]+A[3]+A[4]+A[5]+A[6]+A[7]+A[8];
我们便可以得到C[i]=A[i−2k+1]+A[i−2k+2]+...+A[i];
在这里,k为i的二进制中从最低位到高位连续零的长度
那么,如何求出二进制中从最低位到高位连续零的长度呢?
我们需要引入lowbit
inline int lowbit(int x)
{
     return x&(-x);
}
&运算,即与运算,即按位比较都是1则为1,否则为0。

lowbit的原理简单说一下:
在计算机中二进制是以补码存储的。对于x(x>0),他的补码就是他的本身. 而 [−x]补为[x]补连同符号位取反加一之后的结果 所以[-x]补&[x]补刚好就是最低位1的结果
总结一下规律:x&(-x),当x为0时结果为0;x为奇数时,结果为1;x为偶数时,结果为x中2的最大次方的因子。用处呢就是找最低位的1的位置。
那么我们树状数组的雏形就搭建好了,看看几个基础函数的用法吧。

add修改
inline void adds(int x,int y)
{
        for(int i=x;i<=n;i+=lowbit(i))
             t[i]+=y;
        return ;
}
query查询
inline int query(int x)
{
       int tot=0;
       for(int i=x;i;i-=lowbit(i))
            tot+=t[i];
       return tot;
}

有了上面的模板,我们可以解决基础的实际性问题:

1.单点修改+区间查询
adds(x,y);//在第x个数上加y
query(y)-query(x-1);//求区间x~y的和(前缀和思想)。
【模板】树状数组 1

2.区间修改+单点查询
差分序列第一个数和原来的第一个数一样
差分序列最后比原序列多一个数,即最后一个数的相反数
差分序列求前缀和可得原序列
将原序列区间[L,R]中的元素全部+1,可以转化操作为差分序列L处+1,R+1处-1
根据规律3我们可以得到(s为差分前缀和数组,a为原数组,c为差分数组)
根据上文规律4我们可以得到区间修改代码(设区间为l,r)
adds(l,x),adds(r+1,-x);
query(x)/​/求出第x个数的值
【模板】树状数组 2

 3.区间修改+区间查询
=a[1]+a[2]+a[3]...a[n]
=c[1]+c[1]+c[2]+c[1]+c[2]+c[3]...c[1]+c[2]...+c[n−1]+c[n]=c[1]+c[1]+c[2]+c[1]+c[2]+c[3]...c[1]+c[2]...+c[n−1]+c[n]

 

 

 

 

 

标签:树状,int,差分,区间,数组,序列
来源: https://www.cnblogs.com/smghj/p/15948450.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有