1. 程式人生 > >NOIP提高組——樹狀陣列

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;
}

最後是二維樹狀陣列,程式碼暫時不附上了。