zoukankan      html  css  js  c++  java
  • 树状数组的基本操作

    理解:二进制末位次方为该位置管辖的范围,无法管辖的范围就是该数减去该二进制末位次方,递推往上,直到得到[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
    ",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
    ",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
    ",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
    ",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
    ",ans);
    61             }
    62         }
    63         printf("
    ");
    64     }
    65 }
    66 
    67 int main(){
    68  
    69     solve();
    70 
    71     return 0;
    72 }
  • 相关阅读:
    Ubuntu中pip的疑难杂症
    Python 分类方法记录
    Python 绘制热图
    脚本学习
    Ubuntu 基础使用教程
    机器学习各种相似性度量及Python实现
    Ubuntu 16.04安装R及Rstudio
    机器学习和数据挖掘领域大牛
    vux+vue-cli3.0坑
    函数的抖动以及节流
  • 原文地址:https://www.cnblogs.com/SSummerZzz/p/12489960.html
Copyright © 2011-2022 走看看