树状数组知识总结

问题导入

给定一个长度为n的数组,完成两种操作:
1.修改一个元素(将此数加上k):单点修改
2.输出区间[l,r]的和 :区间查询
如果暴力的时间复杂度为O(n^2),我们接受不了!
这就要用到树状数组了:

树状数组

在这里插入图片描述
1=(0001) c[1]=a[1]
2=(0010) c[2]=a[1]+a[2]
3=(0011) c[3]=a[3]
4=(0100) c[4]=a[1]+a[2]+a[3]+a[4]
5=(0101) c[5]=a[5]
6=(0110 ) c[6]=a[5]+a[6]
7=(0111) c[7]=a[7]
8=(1000) c[8]=a[1]+a[2]+a[3]+a[4]a[5]+a[6]+a[7]+a[8]
在这之中我们可以看出,c[i]中所加的a数组的数的个数和i的二进制末尾零的个数有关系,
k为i的二进制中从低位到高位连续0的长度,c[i]就加2k个数(从i开始加,往前加2k个数)

c[i]=a[i-2K+1]+a[i-2k+2]+……+a[i]

i=8(1000)时,从8往前加,加8个数
8=(1000) c[8]=a[1]+a[2]+a[3]+a[4]a[5]+a[6]+a[7]+a[8]

末尾连续的零

求末尾有多少个零,我们就是求最后一个1在哪

int lowbit(int t){
	return t&(-t); 
}

这样我们就把末尾有多少零求出来了

c[i]=a[i-lowbit(i)+1]+a[i-lowbit(i)+2]+……+a[i]

单点修改

在这里插入图片描述

从图中我们发现如果修改a[3]的值,那么c[3],c[4],c[8]都会改变,那这之间的规律是什么呢
我们发现:
3(0011)+lowbit(3)=4(0100)
4(0100)+lowbit(4)=8(1000)
一直修改到n就停止

区间查询

在这里插入图片描述

从图中我们发现如果查a[1]~a[7],那么就需要c[7],c[6],c[4],这之间的规律是什么呢
我们发现:
7(0111)-lowbit(7)=6(0110)
6(0110)-lowbit(6)=4(0100)
4(0100)-lowbit(4)=0
用sum数组累加即可
一直到加到i=0就停止

单点修改和区间查询的时间复杂度都为O(logn)

代码总结

void updata (int x,int y){//单点修改
	for(int i=x;i<=n;i+=lowbit(i)){
		c[i]+=y;
	}
}
int downdata(int n){
	int sum=0;
	for(int i=n;i!=0;i-=lowbit(i)){
		sum+=c[i];
	}
	return sum;
}

完整代码(问题导入的问题)

在这里插入图片描述
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值