[toc]ios
#推薦學習樹狀數組的博客:數組
1.[樹狀數組簡單易懂的詳解](https://blog.csdn.net/flushhip/article/details/79165701)學習
2.[能夠代替線段樹的樹狀數組?——樹狀數組進階(1)](https://www.luogu.org/blog/Chanis/super-BIT)spa
#概念.net
樹狀數組顧名思義就是長得像樹的數組(nm這還用你說)code
先放張圖看一下下:blog
這是一顆普通的二叉樹ip
C[i]表明 子樹的葉子結點的權值之和:ci
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[8]=A[1]+A[2]+A[3]+A[4]+A[5]+A[6]+A[7]+A[8];
而後在把他們二進制表示一下:將每個二進制,去掉全部高位1,只留下最低位的1,而後從那個數一直加到1get
1=(001) C[1]=A[1] 2=(010) C[2]=A[1]+A[2] 3=(011) C[3]=A[3] 4=(100) C[4]=A[1]+A[2]+A[3]+A[4] 5=(101) C[5]=A[5] 6=(110) C[6]=A[5]+A[6]; 7=(111) C[7]=A[7] 8=(1000) C[8]=A[1]+A[2]+A[3]+A[4]+A[5]+A[6]+A[7]+A[8]
C[i]=A[i-2^k+1]+A[i-2^k+2]......+A[i] (k爲i的二進制中從最低位到高位連續零的長度)
#define lowbit(i) i&-i
lowbit(x) 其實就是取出x的最低位1 也就是 lowbit(x)=2^k
就是前綴和,好比查詢x到y區間的和,那麼就將從1到y的和-從1到x的和。
從1到y的和求法是,將y轉爲2進制,而後一直減去lowbit(y),一直到0
l find(int x) { ll kkk=0; for(int i=x; i; i-=lowbit(i)) { kkk+=t[i]; } return kkk; }
而若是改變x的值,就要加上本身的lowbit,一直加到n,這些節點都要加,好比一共有8個數第3個數要加上k,那麼c[0011]+=k;
c[0011+0001] (c[0100])+=k;
c[0100+0100] (c[1000])+=k;
這樣就能維護樹狀數組
void insert(int x,int y) { for(int i=x; i<=n; i+=lowbit(i)) { t[i]+=y; } }
這就會變的很好玩。若是將x到y區間加上一個k,那就是從x到n都加上一個k,再從y+1到n加上一個-k
加的移動仍是i+=lowbit(i);
void add(int x,int k) { while(x<=n) { tree[x]+=k; x+=lowbit(x); } }
#include<iostream> #include<cstdio> #include<algorithm> #include<cmath> #include<queue> #include<stack> #include<vector> #include<map> #include<string> #include<cstring> #define ll long long int #define lowbit(i) i&-i #define MAXN 500050 using namespace std; const int maxn=999999999; const int minn=-999999999; inline int read() { char c = getchar(); int x = 0, f = 1; while(c < '0' || c > '9') { if(c == '-') f = -1; c = getchar(); } while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar(); return x * f; } ll t[MAXN],a[MAXN],b[MAXN],ans,n,m; ll find(int x) { ll kkk=0; for(int i=x; i; i-=lowbit(i)) { kkk+=t[i]; } return kkk; } void insert(int x,int y) { for(int i=x; i<=n; i+=lowbit(i)) { t[i]+=y;; } } int main() { n=read(),m=read(); for(int i=1; i<=n; ++i) cin>>a[i],insert(i,a[i]); while(m--) { int p,xx,yy; cin>>p>>xx>>yy; if(p==1) insert(xx,yy); else if(p==2) cout<<find(yy)-find(xx-1)<<'\n'; } return 0; }
#include<iostream> #include<cstdio> #include<algorithm> #include<cmath> #include<queue> #include<stack> #include<vector> #include<map> #include<string> #include<cstring> #define ll long long int #define MAXN 500001 #define lowbit(i) i&-i using namespace std; const int maxn=999999999; const int minn=-999999999; inline int read() { char c = getchar(); int x = 0, f = 1; while(c < '0' || c > '9') { if(c == '-') f = -1; c = getchar(); } while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar(); return x * f; } int t[MAXN],a[MAXN],n,m,ans,last,d[MAXN]; int find(int x) { //單點查詢 int aans=0; /*while(x) { aans+=t[x]; x-=lowbit(x); }*/ for(int i=x; i; i-=lowbit(i)) { aans+=t[i]; } return aans; } void insert(int x,int y) { for(int i=x; i<=n; i+=lowbit(i)) { t[i]+=y; } } int main() { n=read(); m=read(); for(int i=1; i<=n; ++i) { cin>>a[i];
/*這裏很重要*/
/*
這裏運用了差分思想,假設本來的數據存在a數組中,
那麼c數組儲存的就是c[i]=a[i]-a[i-1],若是c[1]=a[1],那麼很明顯
a[i]=c[i]+c[i-1]+c[i-2]+...+c[2]+c[1].
這樣咱們每次單點查詢的時候只要加上c數組的前綴就能夠了。
*/
d[i] = a[i] - a[i-1]; insert(i, d[i]); } while(m--) { int f,xx,yy,zz; cin>>f; if(f==1) { cin>>xx>>yy>>zz; insert(xx,zz); insert(yy+1,-zz);//把多的部分刪掉 } else if(f==2) { cin>>xx; cout<<find(xx)<<'\n'; } } return 0; }
出處:
https://blog.csdn.net/Small_Orange_glory/article/details/81290634)