NOIP提高组——树状数组

树状数组相较于线段树通俗易懂,代码简单。

先写点更新,区间查询。

#include<bits/stdc++.h>
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<cstdio>
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<iostream>
#include<cstdio>
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;
}

最后是二维树状数组,代码暂时不附上了。


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值