树状数组模板类

树状数组

//树状数组类
class BITree
{//树状数组数值处理部分:1~BITree_num
 //实际操作中建议数组开大一点
public:
	BITree(int dim,int x,int y);                    //构造(维数,树状数组长度)
	~BITree();                                      //析构
	int lowbit(int x);                              //求最低位1对应值
	//一维树状数组
	void update_1(int i, int cal);                  //更新点求区间
	void update_1(int pre, int last, int cal);      //更新区间(差分原理),求点
 	int sum_pre_1(int i);                           //求前缀和(更新点)/求点(更新区间)
	int sum_between_1(int pre, int last);           //求区间和(更新点)
	//二维树状数组
	void update_2(int x, int y, int cal);                                   //更新点
	void update_2(int left, int right, int below, int top, int cal);        //更新子矩阵(差分原理),求点
	int sum_pre_2(int x, int y);                                            //求前缀子矩阵
	int sum_between_2(int left, int right, int below, int top);             //求任意子矩阵

private:
	int BITree_num_1;   //一维树状数组长度
	int BITree_num_x;   //二维树状数组x轴长度  
	int BITree_num_y;   //二维树状数组y轴长度
	int BITree_dim;     //树状数组维度
	int* val_1;         //一维树状数组
	int** val_2;        //二维树状数组
};
BITree::BITree(int dim,int x,int y)
{//构造函数
	BITree_dim = dim;    //树状数组维度
	if (dim == 1)
	{//构建一维树状数组参数列表:(1,num,0)
		BITree_num_1 = x;   
		val_1 = new int[x];
		memset(val_1, 0, sizeof(int)*BITree_num_1);
	}
	else
	{//构建一维树状数组参数列表:(2,x,y)
		BITree_num_x = x;
		BITree_num_y = y;
		val_2 = (int**)new int*[x];
		for (int i = 0;i < BITree_num_x;i++)
			val_2[i] = new int[y];
		for (int i = 0;i < BITree_num_x;i++)
			memset(val_2[i], 0, sizeof(int)*BITree_num_y);
	}
}

BITree::~BITree()
{//析构函数
	if (BITree_dim == 1)
	{
		delete[]val_1;
		BITree_num_1 = 0;
	}
	else
	{
		for (int i = 0;i < BITree_num_x;i++)
			delete[]val_2[i];
		BITree_num_x = 0;
		BITree_num_y = 0;
	}
	BITree_dim = 0;
}

int BITree::lowbit(int x)
{//返回二进制数最低位的1对应的数值
	return x & (-x);      //与运算
}

//一维树状数组
void BITree::update_1(int i, int cal)
{//原数组第i个元素加上cal,更新树状数组相关元素
 //可直接用于树状数组的建立
	for (;i <= BITree_num_1;i += lowbit(i))
		val_1[i] += cal;
}
void BITree::update_1(int pre, int last, int cal)
{//更新区间(差分原理)
	BITree::update_1(pre, cal);
	cal = 0 - cal;       //区间末端变为-cal
	BITree::update_1(last+1, cal);
}

int BITree::sum_pre_1(int i)
{//求arry数组的前i项和
 //val为树状数组地址
	int sum = 0;
	for (;i > 0;i -= lowbit(i))       //从后向前每次跳一个lowbit
		sum += val_1[i];
	return sum;
}

int BITree::sum_between_1(int pre, int last)
{//求原数组arry在区间[pre-last]的和
	return sum_pre_1(last) - sum_pre_1(pre - 1);
}

//二维树状数组
void BITree::update_2(int x, int y, int cal)
{//当原数组A[x][y]+cal时,更新树状数组val
	for (int i = x;i <= BITree_num_x;i += lowbit(i))
		for (int j = y;j <= BITree_num_y;j += lowbit(j))
			val_2[i][j] += cal;
}

void BITree::update_2(int left, int right, int below, int top, int cal)
{//更新子矩阵【left】【below】——【right】【top】+cal(差分原理)
	update_2(left, below, cal);
	update_2(right+ 1, top + 1, cal);
	cal = 0 - cal;
	update_2(left, top + 1, cal);
	update_2(right + 1, below, cal);
}

int BITree::sum_pre_2(int x, int y)
{//求A[x][y]左上方的子矩阵A[1--x][1--y]的和
	int sum = 0;
	for (int i = x;i > 0;i -= lowbit(i))
		for (int j = y;j > 0;j -= lowbit(j))
			sum += val_2[i][j];
	return sum;
}

int BITree::sum_between_2(int left, int right, int below, int top)
{//求矩阵A[left--right][below--top]的和
	return sum_pre_2(right, top) - sum_pre_2(right, below - 1) - sum_pre_2(left - 1, top) + sum_pre_2(left - 1, below - 1);
}
### 树状数组的区间修改实现 树状数组是一种高效的数据结构,通常用于处理单点修改和区间查询问题。然而,在某些情况下,也需要支持 **区间修改** 和 **区间查询** 的操作。为了实现这一目标,可以通过引入差分数组的思想来完成。 以下是基于差分数组思想的树状数组区间修改与查询的具体实现: #### 差分数组的概念 差分数组的核心思想是通过对原数组进行预处理,使得对某个区间的加法操作转化为两个单点的操作。对于一个长度为 \( n \) 的数组 \( a[] \),定义其对应的差分数组 \( b[] \) 如下: \[ b[i] = a[i] - a[i-1],\quad (i>0)\] 如果需要将区间 \([l, r]\) 上的所有元素加上 \( x \),则只需执行以下两步操作: 1. 将位置 \( l \) 处的值增加 \( x \): \( b[l] += x \)[^3] 2. 将位置 \( r+1 \) 处的值减少 \( x \): \( b[r+1] -= x \) 最终通过计算前缀和即可恢复原始数组的状态。 --- #### 区间修改与查询的代码模板 下面是一个完整的 C++ 实现,展示了如何利用树状数组支持区间修改和区间查询的功能。 ```cpp #include <bits/stdc++.h> using namespace std; // lowbit 函数 inline int lowbit(int x) { return x & (-x); } // 树状数组class BIT { public: vector<int> tree; int size; // 初始化树状数组 BIT(int n) : size(n), tree(n + 2, 0) {} // 单点更新函数 void update(int idx, int delta) { while (idx <= size) { tree[idx] += delta; idx += lowbit(idx); } } // 前缀和查询函数 int query_prefix(int idx) const { int res = 0; while (idx > 0) { res += tree[idx]; idx -= lowbit(idx); } return res; } // 查询区间 [left, right] 的和 int query_range(int left, int right) const { return query_prefix(right) - query_prefix(left - 1); } }; // 主程序部分 void solve() { int n, q; cin >> n >> q; // 数组大小和询问数量 // 构造两个树状数组分别存储差分数组及其辅助信息 BIT bit_add(n); // 存储 add 操作的结果 BIT bit_subtract(n); // 辅助树状数组,用于修正偏移量 while (q--) { char type; cin >> type; if (type == 'U') { // 更新操作 U l r x 表示给 [l, r] 加上 x int l, r, x; cin >> l >> r >> x; bit_add.update(l, x); // 对应于差分数组中的 add(l, x) bit_add.update(r + 1, -x); // 对应于差分数组中的 add(r+1, -x) bit_subtract.update(l, x * (l - 1)); // 记录偏移量调整项 bit_subtract.update(r + 1, -x * r); // 记录偏移量调整项 } else if (type == 'Q') { // 查询操作 Q k 表示求第 k 位的数值 int k; cin >> k; long long result = bit_add.query_prefix(k) * k - bit_subtract.query_prefix(k); cout << result << "\n"; } } } ``` --- #### 关键点解析 1. **差分数组的作用** 使用差分数组可以将区间修改转换成两次单点修改,从而降低时间复杂度至 \( O(\log n) \)。 2. **双树状数组的设计** 由于直接维护差分数组无法快速获取任意一点的实际值,因此设计了第二个树状数组 `bit_subtract` 来记录偏移量调整项[^4]。 3. **时间复杂度分析** - 修改操作的时间复杂度为 \( O(\log n) \) - 查询操作的时间复杂度同样为 \( O(\log n) \) --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值