NOIP提高組——樹狀陣列
阿新 • • 發佈:2019-02-12
樹狀陣列相較於線段樹通俗易懂,程式碼簡單。
先寫點更新,區間查詢。
#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){
利用了字首和的思想,i&-i個人認為是樹狀陣列最重要的運算。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)); } } }
接著是區間修改,利用了差分的思想,注意一下點修改區間修改時,差分陣列只修改了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; }