树状数组(Binary Indexed Tree(BIT), Fenwick Tree)是一个查询和修改复杂度都为log(n)的数据结构。主要用于查询任意两位之间的所有元素之和,但是每次只能修改一个元素的值。
——百度百科
明确一个概念:
lowbit 取出二进制的最后一个1
x&(-x)
比如说:
6 0000110->0000010 (2)
3 0000011->0000001 (1) -
单点修改
根据这图
A[4]->C[4],C[8]
100->100, 1000
A[3]->C[3],C[4],C[8]
11->11,100,1000
所以 就是 每次加上lowbit
void Add_tarr(int pos,int delta) { for (;pos<=n;) { tarr[pos]+=delta; pos+=pos&(-pos); } }
根据这个 建立tarr数组
就是一边读,一边Add
for (int i=1;i<=n;i++) { scanf("%d",&a[i]); Add_tarr(i,a[i]); }
所以这时候要注意: Add 中 pos <=n 中的 = 不要漏掉,因为 build过程最后一个元素 pos==n
查询前缀和
还是上面那张图
7->c[7]+c[6]+c[4]
111->111+110+100
5->c[5]+c[4]
101->101+100
3->c[3]+c[2]
可以看出 这是pos一直减去lowbit,减到0。
int Qry_tarr(int pos) { int sum=0; for (;pos;) { sum+=tarr[pos]; pos-=pos&(-pos); } return sum; }
所以 就可以用两个前缀和相减来查询区间和。
敌兵布阵 代码
#include<iostream> #include<cstdio> #include<cstring> #define N 50010 using namespace std; int tarr[N],a[N]; int n,T,x,y; char s[10]; void Add_tarr(int pos,int delta) { for (;pos<=n;) { tarr[pos]+=delta; pos+=pos&(-pos); } } int Qry_tarr(int pos) { int sum=0; for (;pos;) { sum+=tarr[pos]; pos-=pos&(-pos); } return sum; } int main() { scanf("%d",&T); for (int I=1;I<=T;I++){ memset(a,0,sizeof(a)); memset(tarr,0,sizeof(tarr)); scanf("%d",&n); for (int i=1;i<=n;i++) { scanf("%d",&a[i]); Add_tarr(i,a[i]); }; printf("Case %d: ",I); for (;1;){ cin>>s; if (s[0]!='E')scanf("%d%d",&x,&y); if (s[0]=='A') Add_tarr(x,y); else if (s[0]=='S') Add_tarr(x,-y); else if (s[0]=='Q') printf("%d ",Qry_tarr(y)-Qry_tarr(x-1)); else break; } } }