树状数组模板大全

树状数组模板大全

int lowbit(int x){return x&(-x);}

一、点更新:

`void update(int x, int y){
	while(x<=n){
		c[x] += y;
		x += lowbit(x);
	}
	//for(int i=x;i<=n;i+=lowbit(i)) c[i] += y;
}`

二、区间查询:

int getsum(int x){
	int ans = 0;
	for(int i=x;i;i-=lowbit(i)) ans += c[i];
	return ans;
}
//i与j区间,用getsum(j)-getsum(i-1)求得 

三、求逆序对:

for(int i=1;i<=n;++i){ scanf("%d",a+i); ++ a[i]; }
    ll sum = 0;
    for(int i=n;i>0;--i){   //Back, < a[i]
        pre[i] = query(a[i]-1);
        sum += pre[i];
        add(a[i]);
    }

四、区间修改,单点查询:
还是利用update和getsum函数,只不过在添加c数组时,是用原数组的差分添加:

FOR(i,1,n) {
        scanf("%d",&a[i]);
        b[i] = a[i] - a[i-1];
    }
    FOR(i,1,n) update(i,b[i]);

五、区间修改、区间查询:
用一个c1数组维护差分数组,区间修改照样用上面的操作,但是区间查询有所不同,这样想在1-q的区间的ans = a[1] + a[2] + a[3] +……+ a[q-1] + a[q],
而在差分数组中,a[1] = c1[1], a[2] = c1[1] + c1[2] , a[3] = c1[1] + c1[2] + c1[3] …
这样下来 ans = q* (c[1]+c[2]+…+c[q]) - (0c[1]+1c[2]+…+(q-1)*c[q]) , 减号前一部分可以用getsum直接算出,但是后面一部分就不同了,应该用c2[i]=(i-1)*c[i]这个数组维护。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e6+5;
int lowbits(int x) { return x & (-x); }
int n, q;
ll c1[maxn], c2[maxn], a[maxn];
void update(ll *t, int i, ll k) {
    while (i <= n) {
        t[i] += k;
        i += lowbits(i);
    }
}
ll getsum(ll *t, int x) {
    ll res = 0;
    while (x) {
        res += t[x];
        x -= lowbits(x);
    }
    return res;
}
int main() {
    scanf("%d%d", &n, &q);
    int i, j, k;
    for (i = 1; i <= n; ++i) {
        scanf("%lld", &a[i]);
        update(c1, i, a[i] - a[i - 1]);
        update(c2, i, (i - 1) * (a[i] - a[i - 1]));
    }
    for (i = 1; i <= q; ++i) {
        int ty, x, y;
        ll z;
        scanf("%d%d%d", &ty, &x, &y);
        if (ty == 1) {
            scanf("%lld", &z);
            update(c1, x, z);
            update(c1, y + 1, -z);
            update(c2, x, (x - 1) * z);
            update(c2, y + 1, -y * z);
        }
		else {
            ll ans;
            ans = y * getsum(c1, y) - getsum(c2, y);
            ans -= (x - 1) * getsum(c1, x - 1) - getsum(c2, x - 1);
            printf("%lld\n", ans);
        }
    }
    return 0;
}

六、二维树状数组(单点修改,区间查询):
思路很简单,update时修改对每个维度都修改即可,而区间查询用简单的容斥原理即可。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll a[5005][5005];
int n, m;
int lowbit(int x) { return x&(-x);}
void update(int x, int y, ll k){
	for(int i=x;i<=n;i+=lowbit(i)){
		for(int j=y;j<=m;j+=lowbit(j)){
			a[i][j] += k;
		}
	}
}
ll getsum(int x, int y){
	ll ans = 0;
	for(int i=x;i>0;i-=lowbit(i)){
		for(int j=y;j>0;j-=lowbit(j)){
			ans += a[i][j];
		}
	}
	return ans;
}


int main(){
	scanf("%d%d",&n,&m);
	int flag;
	while(~scanf("%d",&flag)){
		if(flag == 1){
			int x, y, k;
			scanf("%d%d%d",&x,&y,&k);
			update(x,y,k);
		}
		else {
			int a, b, c, d;
			scanf("%d%d%d%d",&a,&b,&c,&d);
			printf("%lld\n",getsum(c,d) + getsum(a-1,b-1) - getsum(c,b-1) - getsum(a-1,d));
		}
	}
	return 0;
}```

七、二维树状数组区间修改,单点查询:、
思维和一维类似,代码如下:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll a[5005][5005];
int n, m;
int lowbit(int x) {return x&(-x);}
void update1(int x, int y, int k){
	int t = y;
	while(x <=n){
		y= t;
		while(y <=m){
			a[x][y] += k;
			y += lowbit(y);
		}
		x += lowbit(x);
	}
}
void update2(int a, int b, int c, int d, int k){
	update1(a, b, k);
	update1(a, d+1,-k);
	update1(c+1, b, -k);
	update1(c+1, d+1, k);
}
	
ll getsum(int x, int y){
    ll ans = 0;
    int t = y;
    while(x){
   		y = t;
   		while(y){
   			ans += a[x][y];
   			y -= lowbit(y);
   		}
   		x -= lowbit(x);
   	}
   	return ans;
   }
				
int main(){
	scanf("%d%d",&n,&m);
	int flag;
	while(~scanf("%d",&flag)){
		if(flag == 1){
			int a, b, c, d, k;
			scanf("%d%d%d%d%d",&a, &b, &c, &d, &k);
			update2(a, b, c, d, k);
		}else {
			int x, y;
			scanf("%d%d",&x,&y);
			printf("%lld\n",getsum(x,y));
		}
	}
	return 0;
}

八、二维树状数组区间修改区间查询:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 5005;
ll a1[maxn][maxn], a2[maxn][maxn], a3[maxn][maxn], a4[maxn][maxn];
int n, m;
int lowbit(int x) {return x&(-x);}
//单点修改 
void update1(int x, int y, int k){
	for(int i = x;i <= n;i += lowbit(i)){
		for(int j = y;j<=m;j+=lowbit(j)){
			a1[i][j] += 1ll*k;
			a2[i][j] += 1ll*k * x;
			a3[i][j] += 1ll*k * y;
			a4[i][j] += 1ll*k * x * y;
		}
	}
}
//区间修改
void update2(int a, int b, int c, int d, int k){
    update1(a, b, k);
	update1(a, d+1, -k);
	update1(c+1, b, -k);
	update1(c+1, d+1, k);
}
//求前缀和 
ll getsum(int x, int y){
	ll ans = 0;
	for(int i=x;i>0;i-=lowbit(i)){
		for(int j=y;j>0;j-=lowbit(j)){
			ans += (x+1)*(y+1)*a1[i][j] - (y+1)*a2[i][j] - (x+1)*a3[i][j] + a4[i][j];
		}
	}
	return ans ;
}
int main(){
	scanf("%d%d",&n,&m);
	int flag;
	while(~scanf("%d",&flag)){
		if(flag == 1){
			int a, b, c, d, k;
			scanf("%d%d%d%d%d",&a,&b,&c,&d,&k);
			update2(a, b, c,d, k);
		}
		else{
			int a, b, c, d;
			scanf("%d%d%d%d",&a,&b,&c,&d);
			printf("%lld\n",getsum(c,d) - getsum(a-1,d) - getsum(c, b-1) + getsum(a-1, b-1));
		}
	}
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值