【c++】浅析树状数组

惊喜累加器

目录

单点修改+区间查询

代码

区间修改 + 单点查询

修改

查询

代码

区间修改 + 区间查询

查询

代码


单点修改+区间查询

单点修改仍是模板,区间查询[x,y]时,我们利用前缀和的思想,即(sum[y] - sum[x - 1])即可算出答案

代码

#include<cstdio>
#define M 500000
#define low_bit(x) (x & -x)
#define reg register

inline void read(int &x){
    x = 0;
    int f = 1;
    char s = getchar();
    while (s < '0' || s > '9'){
        if (s == '-')
            f = -1;
        s = getchar();
    }
    while (s >= '0' && s <= '9'){
        x = x * 10 + s - '0';
        s = getchar();
    }
    x *= f;
}

int C[M + 5];
int n,m;

void Add(int x,int y){
    for (reg int i = x;i <= n;i += low_bit(i))
        C[i] += y;
    return ;
}

int Query(int x){
    int sum = 0;
    for (reg int i = x;i;i -= low_bit(i))
        sum += C[i];
    return sum;
}

int main(){
    read(n),read(m);
    for (reg int i = 1;i <= n; ++ i){
        int a;
        read(a);
        Add(i,a);
    }
    for (reg int i = 1;i <= m; ++ i){
        int a,b,c;
        read(a),read(b),read(c);
        if (a == 1)
            Add(b,c);
        else printf("%d\n",Query(c) - Query(b - 1));
    }
    return 0;
}

区间修改 + 单点查询

修改

这里引入差分的思想。

设原数组为A,则差分数组B[i] = A[i] - A[i - 1]

这道题跟差分有什么关系呢?(方便解题呀)

设A[6] = {0,1,2,3,4,5}

则B[6] = {0,1,1,1,1,1}

接着在 2 - 4 区间里每个数加一,则

A[6] = {0,1,3,4,5,5}

B[6] = {0,1,2,1,1,0}

由此,我们可看出 B 数组中,B[2] + 1,B[5] - 1

查询

以上面的例子为例,求A[3]的值(显然为4)

我们进行分析:A[3] = A[3] - A[2] + A[2] - A[1] + A[1] - A[0] = B[3] + B[2] + B[1] = A[3] - A[0] = 4

显然就是求B数组的和

代码

#include<cstdio>
#define M 500000
#define low_bit(x) (x & -x)
#define reg register

inline void read(int &x){
    x = 0;
    int f = 1;
    char s = getchar();
    while (s < '0' || s > '9'){
        if (s == '-')
            f = -1;
        s = getchar();
    }
    while (s >= '0' && s <= '9'){
        x = x * 10 + s - '0';
        s = getchar();
    }
    x *= f;
}

int B[M + 5],A[M + 5];
int n,m;

void Add(int x,int y){
    for (reg int i = x;i <= n;i += low_bit(i))
        B[i] += y;
    return ;
}

int Query(int x){
    int sum = 0;
    for (reg int i = x;i;i -= low_bit(i))
        sum += B[i];
    return sum;
}

int main(){
    read(n),read(m);
    for (reg int i = 1;i <= n; ++ i){
        read(A[i]);
        Add(i,A[i] - A[i - 1]);
    }
    for (reg int i = 1;i <= m; ++ i){
        int a;
        read(a);
        if (a == 1){
            int x,y,k;
            read(x),read(y),read(k);
            Add(x,k);
            Add(y + 1,-k);
        }
        else {
            int x;
            read(x);
            printf("%d\n",Query(x));
        }
    }
    return 0;
}

区间修改 + 区间查询

显然修改是不会变的,变的是查询

查询

A[1] + A[2] + A[3] + …+ A[N - 1] + A[N] = B[1] + B[1] + B[2] + B[1] + B[2] + B[3] + … + B[N - 1] + B[N]

                                                               = N * B[1] + (N - 1) * B[2] + … + B[N]

                                                               =  N * (B[1] + B[2] + … + B[N]) - (0 * B[1] + 1 * B[2] + … + (N - 1) * B[N])

因而,我们可以在B数组的基础上再用一个B2数组,令 B2[i] = (i - 1) * (A[i] - A[i - 1])

这样就能很方便的求出答案了。

注: 如果给出区间的左端点 x,不是从一开始的,那么我们可以借鉴 单点修改+区间查询 的前缀和思想(具体操作见代码)

代码

#include<cstdio>
#define lowbit(x) (x & -x)
#define M 100000
#define LL long long
#define reg register

inline void read(int &x){
    x = 0;
    int f = 1;
    char s = getchar();
    while(s < '0' || s > '9'){
        if (s == '-')
            f = -1;
        s = getchar();
    }
    while (s >= '0' && s <= '9'){
        x = x * 10 + s - '0';
        s = getchar();
    }
    x *= f;
}

int n,m;
LL C[M + 5],C2[M + 5];
int A[M + 5];

void update(int x,LL k){
    for (reg int i = x;i <= n;i += lowbit(i)){
        C[i] += k;
        C2[i] += (x - 1) * k;
    }
    return ;
}
LL  query(int x){
    LL sum1 = 0,sum2 = 0;
    for (reg int i = x;i;i -= lowbit(i)){
        sum1 += C[i];
        sum2 += C2[i];
    }
    return sum1 * x - sum2;
}
inline LL Su(int x,int y){
    LL sum =  query(y);
    sum -= query(x - 1);
    return sum;
}

int main(){
    read(n),read(m);
    for (reg int i = 1;i <= n; ++ i){
        read(A[i]);
        update(i,A[i] - A[i - 1]);
    }
    for (reg int i = 1;i <= m; ++ i){
        int pd;
        read(pd);
        if (pd == 1){
            int x,y,k;
            read(x),read(y),read(k);
            update(x,k);
            update(y + 1,-k);
        } else {
            int x,y;
            read(x),read(y);
            printf("%lld\n",Su(x,y));
        }
    }
    return 0;
}

 

期末大作业基于python的足球运动员数据分析源码+数据集(高分项目),个人经导师指导并认可通过的高分设计项目,评审分98分,项目中的源码都是经过本地编译过可运行的,都经过严格调试,确保可以运行!主要针对计算机相关专业的正在做大作业、毕业设计的学生和需要项目实战练习的学习者,资源项目的难度比较适中,内容都是经过助教老师审定过的能够满足学习、使用需求,如果有需要的话可以放心下载使用。 期末大作业基于python的足球运动员数据分析源码+数据集(高分项目)期末大作业基于python的足球运动员数据分析源码+数据集(高分项目)期末大作业基于python的足球运动员数据分析源码+数据集(高分项目)期末大作业基于python的足球运动员数据分析源码+数据集(高分项目)期末大作业基于python的足球运动员数据分析源码+数据集(高分项目)期末大作业基于python的足球运动员数据分析源码+数据集(高分项目)期末大作业基于python的足球运动员数据分析源码+数据集(高分项目)期末大作业基于python的足球运动员数据分析源码+数据集(高分项目)期末大作业基于python的足球运动员数据分析源码+数据集(高分项目)期末大作业基于python的足球运动员数据分析源码+数据集(高分项目)期末大作业基于python的足球运动员数据分析源码+数据集(高分项目)期末大作业基于python的足球运动员数据分析源码+数据集(高分项目)期末大作业基于python的足球运动员数据分析源码+数据集(高分项目)期末大作业基于python的足球运动员数据分析源码+数据集(高分项目)期末大作业基于python的足球运动员数据分析源码+数据集(高分项目)期末大作业基于python的足球运动员数据分析源码+数据集(高分项目)期末大作业基于python的足球运动员数据分析源码+数据集(高分项目)期末大作业基于pyth
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值