inline void add( LL s, LL num ){ while(s<=n) tree[s] += num,s += lowbit(s); return ; } inline LL ask (LL s) { LL ans = 0 ; while ( s >= 1) ans += tree [s] ,s -= lowbit(s); return ans; }
树状数组或者二叉索引树也称做Binary Indexed Tree,又叫作Fenwick树;它的查询和修改的时间复杂度都是log(n)
,空间复杂度则为O(n)
,这是由于树状数组经过将线性结构转化成树状结构,从而进行跳跃式扫描。一般使用在高效的计算数列的前缀和,区间和。html
C1 = A1 C2 = A1+A2 C3 = A3 C4 = A1+A2+A3+A4 C5 = A5 C6 = A5+A6 C7 = A7 C8 = A1+A2+A3+A4+A5+A6+A7+A8
15=(1111)2,经过lowbit分解,它能够变成4个数的和:(1111)2=(1)2+(10)2+(100)2+(1000)2,而后咱们分析这个倒着跳的过程。减去15的最小的2的幂次2^0获得14。减去14的最小的2的幂次2^1获得12。减去12的最小的2的幂次2^2获得8。减去8的最小的2的幂次2^3获得0。git
因此C(15) = C(14) + C(12) + C(8) + C(0),由图也能够得知,其结果是正确的。数组
除此以外,树状数组可以快速的求任意区间的和,设sum(k) = A[1] + A[2] + ... + A[k],则A[i] + A[i+1] + ... + A[j] = sum(j) - sum(i-1)。ide
#include <bits/stdc++.h> #define rep(i,j,n) for(register int i=j;i<=n;i++) #define Rep(i,j,n) for(register int i=j;i>=n;i--) #define low(x) x&(-x) using namespace std ; typedef long long LL ; const int inf = INT_MAX >> 1 ; inline LL In() { LL res(0) , f(1) ; register char c ; #define gc c = getchar() while(isspace(gc)) ; c == '-' ? f = - 1 , gc : 0 ; while(res = (res << 1) + (res << 3) + (c & 15) , isdigit(gc)) ; return res * f ; #undef gc } inline void Ot() { while(1) { int x = In() ; cout << (low(x)) << '\n' ; } } signed main() { // freopen("test.in,"r",stdin) ; return Ot() , 0 ; }
lowbit是最低位 求法:x&(-x)spa
支持手工模拟code
#ifdef Dubug #endif #include <bits/stdc++.h> #define lowbit(x) x&(-x) using namespace std; typedef long long LL ; inline LL In() { LL res(0),f(1); register char c ; while(isspace(c=getchar())) ; c == '-'? f = -1 , c = getchar() : 0 ; while(res = (res << 1) + (res << 3) + (c & 15) , isdigit(c=getchar())) ; return res * f ; } LL n , q ; const int N = 1e6 + 5 ; LL tree[N] ; inline void Add(int x,int y) { for(;x<=n;x+=lowbit(x)) tree[x] += y ; } inline LL ask(int x) { LL ans = 0 ; for(;x>=1;x-=lowbit(x)) ans += tree[x] ; return ans ; } signed main () { n = In() , q = In() ; for(register int i=1;i<=n;i++) { int x ; x = In() ; Add(i,x) ; } for(register int i=1;i<=q;i++) { int x , y , z ; x = In() , y = In() , z = In() ; if(x == 1) Add(y,z) ; if(x == 2) cout << ask(z) - ask(y-1) << endl ; } return 0 ; }
超级树状数组 -> [Here]htm