树状数组在只是单点添加和区间求和的过程中实用效率远大于线段树,所以有必要学习一下(个人见解)
lowbit:i&(-i)
对于单点添加直接使用add就可以完成,如果还有别的操作还可以再另写函数。
对于求和可以直接用 summax 减去 summin-1 就可以求出区间和比、代码复杂度远低于线段树。
以洛谷3374为例:http://daniu.luogu.org/problem/show?pid=3374#sub
第一行包含两个整数N、M,分别表示该数列数字的个数和操作的总个数。
第二行包含N个用空格分隔的整数,其中第i个数字表示数列第i项的初始值。
接下来M行每行包含3或4个整数,表示一个操作,具体如下:
操作1: 格式:1 x k 含义:将第x个数加上k
操作2: 格式:2 x y 含义:输出区间[x,y]内每个数的和
输出格式:
输出包含若干行整数,即为所有操作2的结果。
1 #include<iostream> 2 #include<algorithm> 3 #include<string> 4 using namespace std; 5 #define MAX 500000 6 int N,M; 7 int a[MAX],c[MAX]; 8 //====================================================== 9 void init();// 10 void ADD(int ,int );// 11 int sum(int ); 12 //====================================================== 13 void ADD(int x,int y) 14 { 15 for(int i=x;i<=N;i+=i&(-i) ){ 16 c[i]+=y; 17 } 18 } 19 //====================================================== 20 int sum(int x) 21 { 22 int SUM=0; 23 for(int i=x;i>=1;i-=i&(-i)) 24 SUM+=c[i]; 25 return SUM; 26 } 27 //====================================================== 28 void init() 29 { 30 int aa,bb,cc; 31 cin>>N>>M; 32 for(int i=1;i<=N;i++){ 33 cin>>a[i]; 34 ADD( i , a[i] ); 35 } 36 for(int i=1;i<=M;i++){ 37 cin>>aa>>bb>>cc; 38 if(aa==1)ADD(bb,cc); 39 if(aa==2)cout<<sum(cc)-sum(bb-1)<<endl; 40 } 41 } 42 //====================================================== 43 int main() 44 { 45 init(); 46 return 0 ; 47 }