树状数组的基本操作

理解:二进制末位次方为该位置管辖的范围,无法管辖的范围就是该数减去该二进制末位次方,递推往上,直到得到[1,n]的管辖点,然后相加。某个位置修改,会导致管辖它的点也相应被修改,这关键就是二进制的进位来更新管辖它的点,2^0一定被2^1管辖,2^1一定被2^2管辖。因为二进制的独特性,把这些最关键也是最基本的操作降到了log(n)。

 

一、一维树状数组的基本操作

转载:https://www.cnblogs.com/xenny/p/9739600.html

①单点更新,区间求和

模板:https://www.luogu.com.cn/problem/P3374

 1 #include <iostream>
 2 #include <algorithm>
 3 #include <map>
 4 #include <queue>
 5 #include <string>
 6 #include <stack>
 7 #include <functional>
 8 #include <vector>
 9 #include <numeric>
10 #include <list>
11 #include <cstdio>
12 #include <cstring>
13 #include <cmath>
14 using namespace std;
15 #define ll long long
16 #define pb push_back
17 #define fi first
18 #define se second
19 
20 const int N = 5e5+10;
21 int arr[N];
22 int n,m;
23 
24 inline int lowbit(int x){
25     return x&(-x);
26 }
27 
28 void update(int x,int v){
29     while(x <= n){
30         arr[x] += v;
31         x += lowbit(x);
32     }
33 }
34 
35 int sum(int x){
36     int res = 0;
37     while(x){
38         res += arr[x];
39         x -= lowbit(x);
40     }
41     return res;
42 }
43 
44 void solve(){
45     scanf("%d%d",&n,&m);
46     for(int i = 1; i <= n; ++i){
47         int x;
48         scanf("%d",&x);
49         update(i,x);
50     }
51     int op,x,y;
52     while(m--){
53         scanf("%d%d%d",&op,&x,&y);
54         if(op == 1){
55             update(x,y);
56         }else {
57             printf("%d\n",sum(y) - sum(x-1));
58         }
59     }
60 }
61 
62 int main(){
63  
64     solve();
65 
66     return 0;
67 }

 

②区间修改,单点求值

模板:https://www.luogu.com.cn/problem/P3368

 1 #include <iostream>
 2 #include <algorithm>
 3 #include <map>
 4 #include <queue>
 5 #include <string>
 6 #include <stack>
 7 #include <functional>
 8 #include <vector>
 9 #include <numeric>
10 #include <list>
11 #include <cstdio>
12 #include <cstring>
13 #include <cmath>
14 using namespace std;
15 #define ll long long
16 #define pb push_back
17 #define fi first
18 #define se second
19 
20 const int N = 5e5+10;
21 int c[N],a[N];
22 int n,m;
23 
24 inline int lowbit(int x){
25     return x&(-x);
26 }
27 
28 void update(int x,int v){
29     while(x <= n){
30         c[x] += v;
31         x += lowbit(x);
32     }
33 }
34 
35 int sum(int x){
36     int res = 0;
37     while(x){
38         res += c[x];
39         x -= lowbit(x);
40     }
41     return res;
42 }
43 
44 void solve(){
45     scanf("%d%d",&n,&m);
46     for(int i = 1; i <= n; ++i){
47         scanf("%d",a+i);
48         update(i,a[i] - a[i-1]);
49     }
50     int op;
51     while(m--){
52         scanf("%d",&op);
53         if(op == 1){
54             int x,y,k;
55             scanf("%d%d%d",&x,&y,&k);
56             update(x,k);
57             update(y+1,-k);
58         }else{
59             int x;
60             scanf("%d",&x);
61             printf("%d\n",sum(x));
62         }
63     }
64 }
65 
66 int main(){
67  
68     solve();
69 
70     return 0;
71 }

 

③区间修改,区间求值

模板:https://vjudge.net/problem/POJ-3468

#include <iostream>
#include <algorithm>
#include <map>
#include <queue>
#include <string>
#include <stack>
#include <vector>
#include <list>
#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;
#define ll long long
#define pb push_back
#define fi first
#define se second

const int N = 1e5+10;
ll sum_1[N],sum_2[N],a[N];
int n;

inline int lb(int x){
    return x&(-x);
}

void update(int inx,int v){
    int x = inx;
    while(inx <= n){
        sum_1[inx] += v;
        sum_2[inx] += (ll)v*(x-1);
        inx += lb(inx);
    }
}

ll sum(int inx){
    ll res = 0;
    int x = inx;
    while(inx){
        res += (ll)x*sum_1[inx] - sum_2[inx];
        inx -= lb(inx);
    }
    return res;
}

void solve(){
    int q;
    scanf("%d%d",&n,&q);
    for(int i = 1; i <= n; ++i){
        scanf("%lld",a+i);
        update(i,a[i] - a[i-1]);
    }
    char op[10];
    int a,b,c;
    while(q--){
        scanf("%s",op);
        if(op[0] == 'Q'){
            scanf("%d%d",&a,&b);
            ll ans = sum(b) - sum(a-1);
            printf("%lld\n",ans);
        }else{
            scanf("%d%d%d",&a,&b,&c);
            update(a,c); update(b+1,-c);
        }
    }
}

int main(){
 
  //  ios::sync_with_stdio(false);
  //  cin.tie(0); cout.tie(0);
    solve();

    return 0;
}

 二、二维树状数组的基本操作

①单点修改,区间求值

模板:https://www.acwing.com/problem/content/1271/

 

 1 #include <iostream>
 2 #include <algorithm>
 3 #include <map>
 4 #include <queue>
 5 #include <string>
 6 #include <stack>
 7 #include <functional>
 8 #include <vector>
 9 #include <numeric>
10 #include <list>
11 #include <cstdio>
12 #include <cstring>
13 #include <cmath>
14 using namespace std;
15 #define ll long long
16 #define pb push_back
17 #define fi first
18 #define se second
19 
20 const int N = 1e3+100;
21 int a[N][N];
22 int c[N][N];
23 int n,m;
24 
25 inline int lb(int x){
26     return x&(-x);
27 }
28 
29 void update(int x, int y, int v){
30     a[x][y] += v;
31     for(int i = x; i <= n; i += lb(i))
32         for(int j = y; j <= n; j += lb(j))
33             c[i][j] += v;
34 }
35 
36 int sum(int x,int y){
37     int res = 0;
38     for(int i = x; i >= 1; i -=lb(i))
39         for(int j = y; j >= 1; j -= lb(j))
40             res += c[i][j];
41     return res;
42 }
43 
44 void solve(){
45     scanf("%d",&n);
46     int op;
47     while(scanf("%d",&op) && op != 3){
48         if(op == 1){
49             int x,y,k;
50             scanf("%d%d%d",&x,&y,&k);
51             ++x;++y;
52             swap(x, y);
53             update(x,y,k);
54         }else if(op == 2){
55             int x1,x2,y1,y2;
56             scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
57             ++x1;++x2;++y1;++y2;
58             swap(x1,y1); swap(x2,y2);
59             int tot = sum(x2,y2) - sum(x1-1,y2) - sum(x2,y1-1) + sum(x1-1,y1-1);
60             printf("%d\n",tot);
61         }else break;
62     }
63 }
64 
65 int main(){
66  
67     solve();
68 
69     return 0;
70 }

 

②区间修改,单点求值

题目:https://vjudge.net/problem/POJ-2155

题目解析:https://wenku.baidu.com/view/1e51750abb68a98271fefaa8.html

 

 1 #include <iostream>
 2 #include <algorithm>
 3 #include <map>
 4 #include <queue>
 5 #include <string>
 6 #include <stack>
 7 #include <functional>
 8 #include <vector>
 9 #include <numeric>
10 #include <list>
11 #include <cstdio>
12 #include <cstring>
13 #include <cmath>
14 using namespace std;
15 #define ll long long
16 #define pb push_back
17 #define fi first
18 #define se second
19 
20 const int N = 1e3+100;
21 int c[N][N];
22 int n;
23 
24 inline int lb(int x){
25     return x&(-x);
26 }
27 
28 void update(int x,int y){
29     for(int i = x; i <= n; i += lb(i))
30         for(int j = y; j <= n; j += lb(j))
31             ++c[i][j];
32 }
33 
34 int sum(int x,int y){
35     int res = 0;
36     for(int i = x; i >= 1; i -= lb(i))
37         for(int j = y; j >= 1; j -= lb(j))
38             res += c[i][j];
39 
40     return res;
41 }
42 
43 void solve(){
44     int T,q;
45     scanf("%d",&T);
46     while(T--){
47         memset(c,0,sizeof(c));
48         scanf("%d%d",&n,&q);
49         char op[10];
50         while(q--){
51             scanf("%s",op);
52             if(op[0] == 'C'){
53                 int x1,x2,y1,y2;
54                 scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
55                 update(x1,y1); update(x1,y2+1); update(x2+1,y1); update(x2+1,y2+1);
56             }else{
57                 int x,y;
58                 scanf("%d%d",&x,&y);
59                 int ans = sum(x,y)%2 == 0 ? 0 : 1;
60                 printf("%d\n",ans);
61             }
62         }
63         printf("\n");
64     }
65 }
66 
67 int main(){
68  
69     solve();
70 
71     return 0;
72 }

 

posted @ 2020-03-13 23:43  SummerMingQAQ  阅读(314)  评论(0编辑  收藏  举报