树状数组拓展

本文介绍了一维和二维树状数组的应用技巧,包括单点及区间修改、查询等操作,并通过具体代码示例展示了如何实现这些功能。此外还讨论了如何处理二维矩阵上的矩形修改与查询问题。

(请先复习单点修改,区间求和以及利用差分实现区间修改,单点求和)


区间修改,区间求和(CodeVs-BIT模版)

控制两个树状数组A,B

Add操作(r, k):[1,r]加上k (注意,从l加到r就可以先Add(r,k)再Add(l-1, -k))

Add时,A[r]+=k,B[r]+=k*r

Query操作(r):查询[1,r]的和

Query时,结果就是B[1]~B[n] + r * (A[r+1]~A[n])   (请自行思考) 

这两个累加就用两个树状数组.

#include <iostream>
using namespace std;

typedef long long LL;

LL A[200010], B[200010];
int n, q;

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

LL Query1(int k) {
	LL ans = 0;
	for(int i=k; i; i-=lowbit(i)) ans += A[i];
	return ans;
}
LL Query2(int k) {
	LL ans = 0;
	for(int i=k; i; i-=lowbit(i)) ans += B[i];
	return ans;
}
void Add1(int k, LL x) {
	for(int i=k; i<=n; i+=lowbit(i)) A[i] += x;
}
void Add2(int k, LL x) {
	for(int i=k; i<=n; i+=lowbit(i)) B[i] += x;
}
void Add(int r, int x) { //区间修改 
	if(!r) return;
	Add1(r, x);
	Add2(r, r*x);
}
LL Query(int r) { //区间询问 
	return Query2(r) + r * (Query1(n) - Query1(r));
}
int main() {
	LL x;
	cin >> n;
	for(int i=1; i<=n; i++) {
		cin >> x;
		Add(i, x);
		Add(i-1, -x);
	}
	cin >> q;
	for(int i=1; i<=q; i++) {
		int opt, l, r;
		LL k;
		cin >> opt;
		if(opt == 1) {
			cin >> l >> r >> k;
			Add(r, k);
			Add(l-1, -k);
		} else if(opt == 2) {
			cin >> l >> r;
			cout << Query(r) - Query(l-1) << endl;
		}
	}
	return 0;
}
 


二维矩阵:单点修改,矩形求和

树状数组的维度拓展非常简单,即“数组多一维,循环多一层“
下面是询问操作和修改操作


int Query(int i, int j) {
	int ans = 0;
	for(; i; i-=lowbit(i))
		for(; j; j-=lowbit(i))
			ans += B[i][j];
	return ans;
}

void Add(int i, int j, int x) {
	for(; i<=n; i+=lowbit(i))
		for(; j<=m; j+=lowbit(j))
			B[i][j] += x;
}

而对于非前缀矩形,可以拆成一个比较大大矩形减去两个前缀矩形再加上一个小的重合部分的前缀矩形
(可以自行画图理解)

二维矩阵:矩形修改,矩形求和

写四个二维BIT即可

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值