算是为了明天的线段树的查询做下铺垫吧
树状数组作用:
优点:查询区间和以及前缀和时间复杂度为O(logn),点更新O(nlogn)
缺点:不适合区间更新= =当然区间更新肯定要我们的线段树啦;
下面图源@bilibili_算法训练营
ok这里重点提一下如何确定区间长度
不妨转化下思路,找k个0不妨找二进制表示下第一个1的位置;
对每个i(i>=1),因为我们知道对于任意的i,其补码为-i,所以区间长度len=(-i)&i
比如i=8,二进制为1000,其补码为1000,进行与操作得到1000,即十进制8,所以区间长度即为8;
其他操作感觉没有什么难理解的地方,上代码:
#include<bits/stdc++.h>
using namespace std;
const int N=10001;
int a[N];//存放数据
int c[N];//树状数组
int n;
int lowbit(int i)//c[i]管理的区间长度
{
return (-i)&i;//i的补码与i进行与运算;
}
void add(int i,int z)//更新a[i]的值,维护树状数组
{
for(;i<=n;i+=lowbit(i))//更新c[i]和c[i]的所有祖先;
c[i]+=z;
}
int Get_sum(int i)//计算前缀和
{
int sum=0;
for(;i>=1;i-=lowbit(i))
sum+=c[i];
return sum;
}
int Get_sum(int i,int j)//计算i-j的区间和;
{
return Get_sum(j)-Get_sum(i-1);
}
int main()
{
cin>>n;
for(int i=1;i<=n;i++)//初始化;
{
cin>>a[i];
add(i,a[i]);
}
int x,y;
cin>>x>>y;
cout<<Get_sum(x)<<endl;
cout<<Get_sum(x,y)<<endl;
int i,z;
cin>>i>>z;
add(i,z);
cout<<Get_sum(x)<<endl;
cout<<Get_sum(x,y)<<endl;
}
/*test
5
1 2 3 4 5
2 4
输出:3 9
3 3
输出:3 12
*/