树状数组的使用

树状数组

就差不多这个样子的:
在这里插入图片描述在这里插入图片描述

c [ i ] = a [ i − 2 k + 1 ] + a [ i − 2 k + 2 ] + . . . + a [ i ] c[i]=a[i-2^k+1]+a[i-2^k+2]+...+a[i] c[i]=a[i2k+1]+a[i2k+2]+...+a[i]

lowbit

lowbit操作是求出非负整数x的最后一位1所表示的数值。

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

修改:

void update(int x,int y){
	for(int i=x;i<=n;i+=lowbit(i))
		c[i]+=y;
}

查询:

int getsum(int x){
    int ans=0;
	for(int i=x;i;i-=lowbit(i))
		ans+=c[i];
	return ans;
}

例题

1.单点修改,区间查询

修改:

void update(int x,int y){
	for(int i=x;i<=n;i+=lowbit(i))
		c[i]+=y;
}

查询:

int getsum(int L,int R){//运用前缀和
	int ans = 0;
	for(int i=L-1;i;i-=lowbit(i))
	ans-=c[i];
	for(int i=R;i;i-=lowbit(i))
	ans+=c[i];
	return 0;
}

2.区间修改,单点查询

修改:

void update(int x,int y){
	for(int i=x;i<=n;i+=lowbit(i))
		c[i]+=y;
}
update(L,k);
update(R+1,-k);//这里使用了差分

查询:

int getsum(int x){
    int ans=0;
	for(int i=x;i;i-=lowbit(i))
		ans+=c[i];
	return ans;
}

3.区间修改,区间查询

依旧使用差分,再求前缀和的前缀和

例题:

BIT-3:
题目描述
给定数组 a_1,a_2…a_n,进行 q 次操作,操作有两种:1 l r k:将 a_i~a_k 每个数都加上 k;
2 l r:求 a_l+a_{l+1}…+a_r
输入格式
第一行:输入两个数 n,q,表示给定数组的长度和操作数
第二行:输入 n 个数,表示长度为 n 的给定数组
接下来 q 行:每行输入表示如题的某一种操作
输出格式
对于每个 2 操作,输出对应结果
数据范围

解题思路:

这个题是区间修改,区间查询
可以考虑之前的区间修改,单点查询
单点查询是求差分数组前缀,得到某个点的值a[x]
如果再求一次前缀,就是我们想要的答案sum[x]
找到规律了吗
在等号右侧的式子中,d[1]用了p次,d[2]用了p-1次…
推导公式
所以,维护两个前缀和数组
sum1 维护 d 数组的前缀和
sum2 维护 d*i 的前缀和
区间查询
位置 p 的前缀和即: (p + 1) * sum1 数组中 p 的前缀和 - sum2 数组中 p 的前缀和。区间[l, r]的和即:位置 r 的前缀和 - 位置 l 的前缀和。

AC代码:

请添加图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值