树状数组相较于线段树通俗易懂,代码简单。
先写点更新,区间查询。
#include
using namespace std;
const int MAXN = 500000;
int bit[MAXN+1];
int n,m;
int sum(int i){
int s=0;
while (i>0){
s+=bit[i];
i-=i& -i;
}
return s;
}
void add(int i,int x){
while (i<=n){
bit[i]+=x;
i+=i&-i;
}
}
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++){
int test;
scanf("%d",&test);
add(i,test);
}
while (m--){
int a,b,c;
scanf("%d%d%d",&c,&a,&b);
if(c==1){
add(a,b);
}
else{
printf("%d\n",sum(b)-sum(a-1));
}
}
}
利用了前缀和的思想,i&-i个人认为是树状数组最重要的运算。
接着是区间修改,利用了差分的思想,注意一下点修改区间修改时,差分数组只修改了2个值
#include
using namespace std;
int n,m,a[1000000],bit[1000000];
void add(int i,int v) {
while(i<=n) {
bit[i]+=v;
i+=i&(-i);
}
}
int sum(int i) {
int ans=0;
while(i>0) {
ans+=bit[i];
i-=i&(-i);
}
return ans;
}
int main() {
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) {
scanf("%d",&a[i]);
add(i,a[i]-a[i-1]);
}
for(int i=1;i<=m;i++) {
int op,x,y,k;
scanf("%d",&op);
if(op==1) {
scanf("%d%d%d",&x,&y,&k);
add(x,k); add(y+1,-k);
}
if(op==2) {
scanf("%d",&x);
int ans=sum(x);
printf("%d",ans);
}
}
}
还有是区间修改区间更新
这个是利用了2个树状数组辅助更新。
#include
#include
using namespace std;
#define LL long long
int n,m;
LL bit1[200001],bit0[200001];
void add0(int i,int v) {
while(i<=n) {
bit0[i]+=v;
i+=i&(-i);
}
}
void add1(int i,int v) {
while(i<=n) {
bit1[i]+=v;
i+=i&(-i);
}
}
LL sum0(int i) {
LL ans=0;
while(i>0) {
ans+=bit0[i];
i-=i&(-i);
}
return ans;
}
LL sum1(int i) {
LL ans=0;
while(i>0) {
ans+=bit1[i];
i-=i&(-i);
}
return ans;
}
LL sum(int i){
LL ans=0;
ans=i*sum1(i)+sum0(i);
return ans;
}
int main() {
scanf("%d",&n);
for(int i=1;i<=n;i++) {
int x;
scanf("%d",&x);
add0(i,-x*(i-1));
add1(i,x);
add0(i+1,x*i);
add1(i+1,-x);
}
scanf("%d",&m);
for(int i=1;i<=m;i++) {
int op,x,l,r;
scanf("%d",&op);
if(op==1) {
scanf("%d%d%d",&l,&r,&x);
add0(l,-x*(l-1));
add1(l,x);
add0(r+1,x*r);
add1(r+1,-x);
}
if(op==2) {
scanf("%d%d",&l,&r);
LL ans=sum(r)-sum(l-1);
printf("%lld",ans);
}
}
return 0;
}
最后是二维树状数组,代码暂时不附上了。