• 一天一道算法题——树状数组


    题目【模板】树状数组1:https://www.luogu.com.cn/problem/P3374

    树状数组和线段树差不多,可以处理区间操作,但是处理不了太复杂的区间问题。,不过代码比线段树简洁很多很多!!!时间复杂度都为O(logn)。

    例如,区间[1,8]存储方式如下:

    1 tree[1]=num[1];//001---001
    2 tree[2]=num[2]+num[1];//010---010 001
    3 tree[3]=num[3];//011---011
    4 tree[4]=num[4]+num[3]+num[2]+num[1];//100---100 011 010 001
    5 tree[5]=num[5];//101---101
    6 tree[6]=num[6]+num[5];//110---110 101
    7 tree[7]=num[7];//111---111
    8 tree[8]=num[8]+num[7]+num[6]+num[5]+num[4]+num[3]+num[2]+num[1];///1000---1000 0111 0110 0101 0100 0011 0010 0001

    从注释可以看出存储方式和二进制有关系。

    递推可得,当第x个数加上k时,tree[x]要加k,然后tree[x+x只剩最低位的1]也要加上x,循环往复。

    根据负数在计算机中用补码存储可得k & -k即为x只剩最低位的1。

    如7&-7

    7用二进制表示为111,-7补码形式为001,111&001得001,所以7只剩最低位的1为001.

    AC代码:

    #include<iostream>
    #include<stdio.h>
    #include<algorithm>
    #define maxn 500010
    typedef long long ll;
    using namespace std;
    
    int n;
    ll tree[maxn << 2];
    
    int lowbit(int k) {
        return k & -k;
    }
    
    void add(int x, ll k) {
        while (x <= n) {
            tree[x] += k;
            x += lowbit(x);
        }
    }
    ll sum(int x) {
        ll ans = 0;
        while (x != 0) {
            ans += tree[x];
            x -= lowbit(x);
        }
        return ans;
    }
    
    int main() {
        int m, k, x, y;
        ll a;
        scanf("%d%d", &n, &m);
        for (int i = 1; i <= n; i++) {
            scanf("%lld", &a);
            add(i,a);
        }
        while (m--) {
            cin >> k;
            if (k == 1) {
                scanf("%d%lld", &x, &a);
                add(x,a);
            }
            else {
                scanf("%d%d", &x, &y);
                if (x <= y)
                    cout << sum(y)-sum(x-1)<< endl;
            }
        }
        return 0;
    }
    View Code

    O(∩_∩)O哈哈~

    补充一道区间加k的操作。

    用差分思想和树状数组结合。

    设数组a[]={1,6,8,5,10},那么差分数组b[]={1,5,2,-3,5}

    也就是说b[i]=a[i]-a[i-1];(a[0]=0;),则递推可得:a[i]=b[1]+....+b[i]

    所以对区间[x,y]进行修改,只用修改b[x]与b[y+1]:

    b[x]=b[x]+k;b[y+1]=b[y+1]-k;

    #include<iostream>
    #include<stdio.h>
    #include<algorithm>
    #define maxn 500010
    typedef long long ll;
    using namespace std;
    
    int n,a[maxn];
    ll tree[maxn << 2];
    
    int lowbit(int k) {
        return k & -k;
    }
    
    void add(int x, ll k) {
        while (x <= n) {
            tree[x] += k;
            x += lowbit(x);
        }
    }
    ll sum(int x) {
        ll ans = 0;
        while (x) {
            ans += tree[x];
            x -= lowbit(x);
        }
        return ans;
    }
    
    int main() {
        int m,x, y;
        ll k;
        scanf_s("%d%d", &n, &m);
        for (int i = 1; i <= n; i++) {
            scanf_s("%d", &a[i]);
            add(i,a[i]-a[i-1]);
        }
        while (m--) {
            cin >> k;
            if (k == 1) {
                scanf_s("%d%d%lld", &x, &y,&k);
                add(x, k); 
                add(y + 1, -k);
            }
            else {
                scanf_s("%d", &x);
                cout << sum(x)<< endl;
            }
        }
        return 0;
    }
    View Code

    (^o^)/~

  • 相关阅读:
    lucene中创建索引库
    商城后台上架商品列表查询的书写全过程
    Linux命令英文全称
    商品品牌分页、过滤、排序查询的完成流程
    axios使用步骤详解(附代码)
    使用CORS处理跨域请求
    npm 是干什么的?
    Mybatis通用Mapper介绍和使用
    FastDFS的理解和分析
    CDN服务的含义
  • 原文地址:https://www.cnblogs.com/zyyz1126/p/12603354.html
Copyright © 2020-2023  润新知