1. 程式人生 > >樹狀陣列模板類

樹狀陣列模板類

樹狀陣列

//樹狀陣列類
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);
}