一维树状数组入门

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 }
View Code

第二类:区间修改,单点查询

    例题: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 }
View Code

 

 

第三类:区间修改,区间查询

    例题: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 }
View Code

 

以上是关于一维树状数组入门的主要内容,如果未能解决你的问题,请参考以下文章

蓝桥杯备赛--带你入门树状数组

二维树状数组入门题 poj2642Stars

一维树状数组区间更新区间查询

树状数组基础

学习笔记——二维树状数组

树状数组_一维