一维树状数组入门
Posted swsyya
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了一维树状数组入门相关的知识,希望对你有一定的参考价值。
个人觉得非常棒的博客:https://www.cnblogs.com/xenny/p/9739600.html
第一类:单点更新,区间查询
例题:http://acm.hdu.edu.cn/showproblem.php?pid=1166
AC代码:
1 /* */ 2 # include <iostream> 3 # include <cstdio> 4 # include <cstring> 5 # include <string> 6 # include <cstdlib> 7 # include <queue> 8 # include <stack> 9 # include <vector> 10 # include <map> 11 # include <set> 12 # include <cmath> 13 # include <bitset> 14 # include <functional> 15 using namespace std; 16 17 int n, m; 18 int a[50005], c[50005];///对应原数组和树状数组 19 int lowbit(int x) 20 { 21 return x&(-x);///当x为0时结果为0,当x为奇数时,结果为1; 22 ///当x为偶数时,结果为x中2的最大次方的因子 23 ///2^k=i&(-i) 24 } 25 26 void updata(int i, int k)///在第i个位置上加上k 27 { 28 while( i<=n )///a[i]包含于c[i+2^k], c[i+2^k+2^k], c[i+2^k+2^k+2^k], ,,, 29 { 30 c[i] += k; 31 i += lowbit(i); 32 } 33 } 34 35 int getsum(int i) 36 { 37 int res=0; 38 while( i>0 ) 39 { 40 res += c[i]; 41 i -= lowbit(i); 42 } 43 return res; 44 } 45 46 int main() 47 { 48 int t; 49 cin>>t; 50 for(int tot=1; tot<=t; tot++ ) 51 { 52 cout<<"Case "<<tot<<":"<<endl; 53 memset(a, 0, sizeof(a)); 54 memset(c, 0, sizeof(c)); 55 cin>>n; 56 for(int i=1; i<=n; i++ ) 57 { 58 cin>>a[i]; 59 updata(i, a[i]); 60 } 61 62 string s; 63 int x, y; 64 while( cin>>s && s[0]!=\'E\' ) 65 { 66 cin>>x>>y; 67 if( s[0]==\'Q\') 68 { 69 int sum=getsum(y)-getsum(x-1); 70 cout<<sum<<endl; 71 } 72 else if( s[0]==\'A\' ) 73 { 74 updata(x, y); 75 } 76 else if( s[0]==\'S\' ) 77 { 78 updata(x, -y); 79 } 80 } 81 } 82 return 0; 83 }
第二类:区间修改,单点查询
例题:http://acm.hdu.edu.cn/showproblem.php?pid=1556
AC代码:
1 /* 一位数状数组:区间修改,单点查询 */ 2 # include <iostream> 3 # include <stdio.h> 4 # include <string.h> 5 # include <string> 6 # include <algorithm> 7 # include <cmath> 8 # include <cstdlib> 9 # include <cctype> 10 # include <deque> 11 # include <climits> 12 # include <queue> 13 # include <stack> 14 # include <set> 15 # include <bitset> 16 # include <list> 17 # include <map> 18 using namespace std; 19 20 # define LL long long 21 # define lowbit(x)(x&(-x)) 22 # define gcd(a, b) __gcd(a, b) 23 # define INF 0x3f3f3f3f 24 # define N 100010 25 26 int c[N];///树状数组不一定是求和 27 28 void updata(int x, int val) 29 { 30 while( x<=N ) 31 { 32 c[x] += val; 33 x += lowbit(x); 34 } 35 } 36 37 int getsum(int x) 38 { 39 int res=0; 40 while( x>0 ) 41 { 42 res += c[x]; 43 x -= lowbit(x); 44 } 45 return res; 46 } 47 48 int main() 49 { 50 int n, x, y, i; 51 while( ~ scanf("%d", &n) && n ) 52 { 53 memset(c, 0, sizeof(c)); 54 for(i=0; i<n; i++ ) 55 { 56 scanf("%d %d", &x, &y); 57 updata(x, 1); 58 updata(y+1, -1); 59 } 60 61 for(i=1; i<=n-1; i++ ) 62 printf("%d ", getsum(i)); 63 printf("%d\\n", getsum(n)); 64 } 65 return 0; 66 }
第三类:区间修改,区间查询
例题:http://poj.org/problem?id=3468
AC代码:
1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #include <algorithm> 5 using namespace std; 6 typedef long long ll; 7 const int maxn=100010; 8 ll sum1[maxn]; 9 ll sum2[maxn]; 10 ll a[maxn]; 11 int n,m; 12 int lowbit(int i){ 13 return i&(-i); 14 } 15 16 void updata(int i,ll k){ 17 int x=i; 18 while(i<=n){ 19 sum1[i]+=k; 20 sum2[i]+=k*(x-1); 21 i+=lowbit(i); 22 } 23 } 24 25 ll getsum(int i){ 26 ll res=0; 27 int x=i; 28 while(i>0){ 29 res+=x*sum1[i]-sum2[i]; 30 i-=lowbit(i); 31 } 32 return res; 33 } 34 35 int main() 36 { 37 while(~scanf("%d%d",&n,&m)){ 38 memset(sum1,0,sizeof(sum1)); 39 memset(sum2,0,sizeof(sum2)); 40 for(int i=1;i<=n;i++){ 41 scanf("%lld",&a[i]); 42 updata(i,a[i]-a[i-1]); 43 } 44 char s[10]; 45 while( m-- ){ 46 scanf("%s",s); 47 if( s[0]==\'C\'){ 48 int x,y,c; 49 scanf("%d%d%d",&x,&y,&c); 50 updata(x,c); 51 updata(y+1,-c); 52 } 53 else{ 54 int x,y; 55 scanf("%d%d",&x,&y); 56 ll sum=getsum(y)-getsum(x-1); 57 cout<<sum<<endl; 58 } 59 } 60 } 61 return 0; 62 }
以上是关于一维树状数组入门的主要内容,如果未能解决你的问题,请参考以下文章