我们还是用一道题来举例子吧
这里是题干:https://www.luogu.org/problemnew/show/P2068
首先,我们要引入一个神奇的东西:lowbit,我们用它来表示一个数的二进制的末尾有多少个0,我们可以用&运算来实现,
lowbit(x)=x&(-x);
之后我们用s[i]来表示从i开始到i-lowbit(i)+1个数的a的值,接着我们用sum[i]来表示前缀和,由于a数组是一个动态的数组,我们不能直接用a数组来加,我们先用改变的a数组来更新和他有关的s数组
所以sum[n]=s[n]加上一个数,由于sum[n]是表示a[1]+a[2]+…+a[n],s[n]=a[n]+a[n-1]+…a[n-lowbit(n)+1],所以还剩下a[1]到a[n-lowbit(n)],这又等于s[n-lowbit(n)]加上一个数,所以sum的状态转移方程为:
sum[n]=s[n]+sum[n-lowbit(n)];
下面我们来考虑一下改变a[x]对哪些s有影响:
首先x以前的s数组撑死用到x-1,所以都没有影响;
s[x]是一定要用到a[x]的,毋庸置疑~~
和sum数组的差不多,所有x+lowbit(x)可以到达的点都是 要用到a[x]的
最后附上代码:
#include<iostream>
using namespace std;
const int maxN=100100;
int n,w,a[maxN],s[maxN],sum[maxN];
int ans,num;
inline int lowbit(int x){
return x&(-x);
}
void preoperate()
{
for(int i=1;i<=n;++i){
for(int j=i;j>=i-lowbit(i)+1;--j)
s[i]+=a[j];
}
}
void change(int p,int value)
{
while(p<=n){
s[p]+=value;
p+=lowbit(p);
}
}
int findsum(int x)
{
int t=0;
while(x>0){
t+=s[x];
x-=lowbit(x);
}
return t;
}
int main()
{
//freopen("testdata.in","r",stdin);
//freopen("shuzhuangshuzu.out","w",stdout);
cin>>n>>w;
for(int i=1;i<=w;++i){
char ch;
int p,q;
cin>>ch>>p>>q;
if(ch=='x'){
change(p,q);
}
if(ch=='y'){
cout<<findsum(q)-findsum(p-1)<<endl;
}
}
return 0;
}