树状数组学习总结

使用情况:  1. 单点增减修改求区间总和(我愿称之为升级版前缀和

                    2.区间增减修改求单点

程序实现:

    (1) 单点增减修改求区间总和:

                  原理:前缀和是用c[n]记录 1 ~ n 之和,而树状数组则相当于建了一棵树,

                             而c[n]记录n这个节点为根的子树中所有节点的和。

                  操作:为了建一棵树并在树上进行修改,我们需要引入一个概念:lowbit

                             lowbit是指一个二进制数的最低位的1的权值。

                             例:lowbit(1) = 1 , lowbit(2)= 2 , lowbit(3) = 1 , lowbit(4)= 4

                             然后,我们可以利用lowbit(n)来表示以n为根节点的子树的叶子节点的个数,

                             并以此为基础建树。  

                                       

                              其中,c[n]记录 n - lowbit(n)  +1 ~ n 的格子之和。 

                              接下来我们要处理如何更新这棵树的问题。

                              假如我们要将第二格的格子+2,那么会影响C[2] , C[4]。

                              那么,当我们Cn时,我们要继续把后面的C[n+lowbit(n)]也更新

                              直到n+lowbit(n)超过范围。

                              最后我们处理区间总和,假如我们要求[L,R]范围内的和,

                              那么我们可以用前缀和[1,R] - [1,L]来求。

                              现在我们的问题变为了如何求[1,n]。

                              假如我们要求[1,4],[1,4] = C4

                              假如我们要求[1,5],[1,5] = C5 + C4

                              我们只要一直加前面子树的总和即可,而我们可用n - lowbit(n)跟踪前面子树的位置。

                  参考程序:

#include<iostream>
#include<cstdio>
#include<algorithm>
  using namespace std;
int n,m;
int a[500005],b[500005],c[500005];
inline int lowbit(int x){return x&(-x);}
void update(int i,int k)
{
	while(i <= n)
	{
		c[i] += k;
		i += lowbit(i);
	}
}
int Sum(int i)
{
	int sum1 = 0;
	while(i > 0)
	{
		sum1 += c[i];
		i -= lowbit(i);
	}
	return sum1;
}
int main()
{
	cin>>n>>m;
	a[0] = 0;
	for(int i=1;i<=n;i++)
	{
		cin>>a[i];
		update(i,a[i]);
	}
	for(int i=1;i<=m;i++)
	{
		int f;
		cin>>f;
		if(f == 1)
		{
			int x,k;
			cin>>x>>k;
			update(x,k);
		}
		else if(f == 2)
		{
			int L,R;
			cin>>L>>R;
			cout<<Sum(R) - Sum(L-1)<<endl;
		}
	}
	return 0;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值