学习参考:
https://blog.csdn.net/flushhip/article/details/79165701
https://blog.csdn.net/moep0/article/details/52770728
https://blog.csdn.net/code12hour/article/details/46597025
https://baike.baidu.com/item/%E6%A0%91%E7%8A%B6%E6%95%B0%E7%BB%84/313739?fr=aladdin
树状数组在寒假集训的时候其实有讲过,但是当时只是有了板子,没有很深地去学习理解,现在回来想去理解一下这个很好用的数据结构。
树状数组的作用
树状数组是对于一个用来处理动态更新、动态统计区间问题的一种良好的数据结构,查询和修改复杂度都为O(logn)的数据结构。
树状数组主要对于单点修改,区间查询进行操作。
lowbit()
比如求出2^p(其中p: x 的二进制表示数中, 右向左数第一个1的位置),如6的二进制表示为110,向左数第零个为0,第一个为1,则p=1,故Lowbit(6) = 2^1 = 2。
lowbit这个的主要作用是求一个数二进制中最低一位的1,常用的lowbit函数很巧地运用了负整数补码的特性。代码如下
int lowbit(int x) { return x&(-x); }
几个操作:把第i个数加上x,修改第i个数的值,删除第i个数,统计第i到第j个数的和
树状数组的原理是增加一个辅助序列C数组,令C[i]=a[i-2k+1]+a[i-2k+2]+…+a[i],其中k为i在二进制形式下末尾0的个数。
树状数组的更新时从给定的那个点开始,一直更新到第n个点为止。
树状数组是一个可以高效的进行区间统计的数据结构,它的本质即为将区间和通过某个特定的函数分为几段存到数组中,树状数组中的元素值对应原序列某一段特定区间的区间和,所以它可以进行区间查询和更新点,所以树状数组常见于区间求和问题。
首先来介绍一下树状数组的原理。首先,每个整数都能以二进制的方式表示,即由一段连续的0和1表示,0代表没有,1代表有。如:13=1101(2)。记lowbit表示为x的二进制表示中的最后一个1。通过函数lowbit(x)=x&(-x )可以求得该数。这样,我们建立一个一维数组tree[],其中tree[i]表示[i-lowbit(i)+1,i]这个区间内所有元素的和。这样,我们就写出了一个树状数组。具体的记录方式如下图所示。
从上图能看出来每一个数的父节点就是右边比自己末尾零个数多的最近的一个
1 #include2 #define fi first 3 #define se second 4 #define pb push_back 5 #define fio ios::sync_with_stdio(false);cin.tie(0); 6 #define pii pair 7 #define vi vector 8 #define vc vector 9 #define mii map 10 #define si(a) scanf("%d",&a) 11 #define ss(a) scanf("%s",&a) 12 #define sl(a) scanf("%I64d",&a); 13 #define slf(a) scanf("%lf",&a); 14 #define CLEAR(a,b) memset(a,b,sizeof(a)) 15 #define pi acos(-1) 16 17 typedef double db; 18 typedef long long ll; 19 typedef unsigned long long ull; 20 21 const int INF=0x3f3f3f3f; 22 const int N=2e5+5; 23 using namespace std; 24 int s[N]; 25 int n; 26 int lowbit(int x) 27 { 28 return x&(-x); 29 } 30 31 void add(int i,int j) 32 { 33 while (i<=n) 34 { 35 s[i]+=j; 36 i+=lowbit(i); 37 } 38 } 39 40 41 int Query(int k) 42 { 43 int re=0; 44 while (k>0) 45 { 46 re+=s[k]; 47 k-=lowbit(k); 48 } 49 return re; 50 } 51 52 53 void sub(int i,int j) 54 { 55 while (i<=n) 56 { 57 s[i]-=j; 58 i+=lowbit(i); 59 } 60 } 61 62 63 int main() 64 { 65 66 }
例题:HDU1556