NOIP提高组——树状数组

来源:互联网 发布:知天下资源吧账号分享 编辑:程序博客网 时间:2024/05/29 18:24

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

先写点更新,区间查询。

#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 longint 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;}
最后是二维树状数组,代码暂时不附上了。


原创粉丝点击