参考博客
https://www.cnblogs.com/xenny/p/9739600.html
https://www.cnblogs.com/RabbitHu/p/BIT.html
https://blog.csdn.net/bestsort/article/details/80796531
理论方面和具体的应用方面可以参考上面博客
这里直接贴模板
单点跟新+区间查询(普通建树)
int n;
int a[50005],c[50005]; //对应原数组和树状数组
int lowbit(int x){
return x&(-x);
}
void updata(int i,int k){ //在i位置加上k
while(i <= n){
c[i] += k;
i += lowbit(i);
}
}
int getsum(int i){ //求A[1 - i]的和
int res = 0;
while(i > 0){
res += c[i];
i -= lowbit(i);
}
return res;
}
单点查询+区间更新(差分建树)
int n,m;
int a[50005] = {0},c[50005]; //对应原数组和树状数组
int lowbit(int x){
return x&(-x);
}
void updata(int i,int k){ //在i位置加上k
while(i <= n){
c[i] += k;
i += lowbit(i);
}
}
int getsum(int i){ //求D[1 - i]的和,即A[i]值
int res = 0;
while(i > 0){
res += c[i];
i -= lowbit(i);
}
return res;
}
int main(){
cin>>n;
for(int i = 1; i <= n; i++){
cin>>a[i];
updata(i,a[i] - a[i-1]); //输入初值的时候,也相当于更新了值
}
//[x,y]区间内加上k
updata(x,k); //A[x] - A[x-1]增加k
updata(y+1,-k); //A[y+1] - A[y]减少k
//查询i位置的值
int sum = getsum(i);
return 0;
}
区间更新+区间查询
维护两个数状数组,sum1[i] = D[i],sum2[i] = D[i]*(i-1);
int n,m;
int a[50005] = {0};
int sum1[50005]; //(D[1] + D[2] + ... + D[n])
int sum2[50005]; //(1*D[1] + 2*D[2] + ... + n*D[n])
int lowbit(int x){
return x&(-x);
}
void updata(int i,int k){
int x = i; //因为x不变,所以得先保存i值
while(i <= n){
sum1[i] += k;
sum2[i] += k * (x-1);
i += lowbit(i);
}
}
int getsum(int i){ //求前缀和
int res = 0, x = i;
while(i > 0){
res += x * sum1[i] - sum2[i];
i -= lowbit(i);
}
return res;
}
int main(){
cin>>n;
for(int i = 1; i <= n; i++){
cin>>a[i];
updata(i,a[i] - a[i-1]); //输入初值的时候,也相当于更新了值
}
//[x,y]区间内加上k
updata(x,k); //A[x] - A[x-1]增加k
updata(y+1,-k); //A[y+1] - A[y]减少k
//求[x,y]区间和
int sum = getsum(y) - getsum(x-1);
return 0;
}
区间修改、单点查询模板题目:https://www.luogu.org/problemnew/show/P3368
区间修改、区间查询模板题目:https://vjudge.net/problem/POJ-3468
二维树状数组
参考博客:https://blog.csdn.net/zzti_xiaowei/article/details/81053094
感觉讲的非常不错,例子应该花了不少时间,很容易懂
单点修改+区间查询
const int maxn = 1003;
int maps[maxn][maxn];
int lowbit(int x)
{
return x & (-x);
}
void add(int x , int y , int d)
{
for(int i = x ; i < maxn ; i += lowbit(i))
{
for(int j = y ; j < maxn ; j += lowbit(j))
{
maps[i][j] += d;
}
}
}
void init()//可要可不要
{
memset(maps , 0 , sizeof(maps));
for(int i = 1 ; i < maxn; i ++)
{
for(int j = 1 ; j < maxn ; j ++)
{
add(i , j , 1);
}
}
}
int sum(int x , int y)//求的是map[1][1]到map[x][y]的矩阵和
{
int res = 0;
for(int i = x ; i > 0 ; i -= lowbit(i))
{
for(int j = y ; j > 0 ; j -= lowbit(j))
{
res += maps[i][j];
}
}
return res;
}
int query(int x1,int y1,int x2,int y2){ //区间查询,[x1][y1]到[x2][y2]的子矩阵
return sum(x2,y2)+sum(x2,y2)-sum(x2,y1-1)-sum(x1-1,y2); //容斥,注意是否可能超longlong
}
区间修改+单点查询
//区间修改,单点查询,和一维树状数组差分思想一样,差分思想。
//二维前缀和:
//sum[i][j]=sum[i−1][j]+sum[i][j−1]−sum[i−1][j−1]+a[i][j]
//那么我们可以令差分数组d[i][j] 表示 a[i][j] 与 a[i−1][j]+a[i][j−1]−a[i−1][j−1] 的差。
void regionUpdate(int x1,int y1,int x2,int y2,int val){
add(x1,y1,val);
add(x2+1,y1,-val);
add(x1,y2+1,-val);
add(x2+1,y2+1,val);
}
int pointQuery(int x,int y){
return sum(x,y);
}
区间更新+区间查询
ll n, m, Q;
ll t1[N][N], t2[N][N], t3[N][N], t4[N][N];
void add(ll x, ll y, ll z){
for(int X = x; X <= n; X += X & -X)
for(int Y = y; Y <= m; Y += Y & -Y){
t1[X][Y] += z;
t2[X][Y] += z * x;
t3[X][Y] += z * y;
t4[X][Y] += z * x * y;
}
}
void range_add(ll xa, ll ya, ll xb, ll yb, ll z){ //(xa, ya) 到 (xb, yb) 的矩形
add(xa, ya, z);
add(xa, yb + 1, -z);
add(xb + 1, ya, -z);
add(xb + 1, yb + 1, z);
}
ll ask(ll x, ll y){
ll res = 0;
for(int i = x; i; i -= i & -i)
for(int j = y; j; j -= j & -j)
res += (x + 1) * (y + 1) * t1[i][j]
- (y + 1) * t2[i][j]
- (x + 1) * t3[i][j]
+ t4[i][j];
return res;
}
ll range_ask(ll xa, ll ya, ll xb, ll yb){
return ask(xb, yb) - ask(xb, ya - 1) - ask(xa - 1, yb) + ask(xa - 1, ya - 1);
}