IndexTree以及应用

文章目录

  • IndexTree
    • IndexTree的前缀和数组
    • 代码实现
    • 二维IndexTree


IndexTree

IndexTree可以以O(logN)的时间得到任意前缀和,并同时支持在O(logN)时间内支持动态单点值的修改。空间复杂度O(N)。
相比于线段树对一段区间进行修改,IndexTree适合对数组的单点进行修改。因为线段树如果进行单点修改,那么它大量的非叶子节点都要进行修改。

IndexTree的前缀和数组

不同于一般的前缀和数组,IndexTree前缀和数组0位置抛弃不用。
IndexTree前缀和数组第 i 位置,将i转化成二进制,将最后边的1削掉,然后加1,假设得到的数是x,原数组中x~i的和就是第 i 位置所填的值。

假设 i 为8,它的二进制序列为1000,我们将它最右边的1消掉再将这个数加1:也就是0000+1=0001,他前缀和的范围就是消去最右边1的数+1到他本身也就是1~8,也就是说原数组第1个数到第8个数的累加和放到IndexTree的前缀和数组第8个位置。

比如求1~33的累加和,33的二进制为100001,那它的累加和就是它本身加上累加和数组中第32(100000)个位置,因为第32个位置的前缀和就是原数组中0~100000位置的和。

代码实现

DP34 【模板】前缀和

#include
#include
#include
#include
using namespace std;

class IndexTree {
public:
	//下标从1开始
	IndexTree(int size)
		:tree(size + 1)
		, n(size)
	{}
	//从1~index的累加和
	long long sum(int index) 
	{

		long long ret = 0;
		while (index > 0) 
		{
			//index&-index:提取index最右侧的1来
			// 
			//比如我们要求1~12位置的累加和
			//12的二进制位1100,先加上tree[1100]
			//因为tree[1100]的位置是1001~1100的累加和
			//再将最右端的1去掉,加上tree[1000]
			//tree[1000]的位置是1~1000的累加和
			ret += tree[index];
			index -= (index & -index);
		}
		return ret;
	}
	void add(int index, int d) 
	{
		//index&-index:提取index最右侧的1来
		//给index位置加上d,那么其他位置也会受到影响
		// 
		//比如给1位置加上d,
		// 2位置是1~2的和,8位置是1~8的和,4位置是1~4的和
		//这些位置都得加上d
		while (index <= n) 
		{
			tree[index] += d;
			index += (index & -index);
		}
	}
	//求从原数组中index1~index2的和
	long long RangeSum(int index1, int index2) 
	{
		return sum(index2) - sum(index1);
	}
private:
	vector<long long>tree;
	int n;
};
int main()
{
    int n=0,q=0;
    cin>>n>>q;
    vector<long long>v(n);
    IndexTree indexTree(n);
    for(int i=0;i<n;i++)
    {
        cin>>v[i];
        indexTree.add(i+1,v[i]);
    }
    while(q--)
    {
        int index1,index2;
        cin>>index1>>index2;
        cout<<indexTree.RangeSum(index1-1,index2)<<endl;
    }
}

二维IndexTree

indexTree相比线段树的优点就是indexTree改成二维的非常的容易的改。indexTree在二维中同样的第一行和第一列的位置是空出来不使用的,这与一维的类似,而在二维中求累加和和一维的原理一样,只不过是多了列。更新也是一样的原理只不过比一维的多了列。
817 · 范围矩阵元素和-可变的

class NumMatrix {
public:
    vector<vector<int>>tree;
    vector<vector<int>>nums;
    int N;
    int M;
    NumMatrix(vector<vector<int>> matrix) 
    {
        if(matrix.size()==0||matrix[0].size()==0)
        {
            return;
        }
        N=matrix.size();
        M=matrix[0].size();
        tree.resize(N+1,vector<int>(M+1));
        nums.resize(N,vector<int>(M));
        for(int i=0;i<N;i++)
        {
            for(int j=0;j<M;j++)
            {
                update(i,j,matrix[i][j]);
            }
        }
    }
    //从(1,1)到(row,col)的累加和
    int sum(int row,int col)
    {
        int res=0;
        for(int i=row+1;i>0;i-=i&(-i))
        {
            for(int j=col+1;j>0;j-=j&(-j))
            {
                res+=tree[i][j];
            }
        }
        return res;
    }
    void update(int row, int col, int val) {
        if(N==0||M==0)
        {
            return;
        }
        int add=val-nums[row][col];
        nums[row][col]=val;
        for(int i=row+1;i<=N;i+=i&(-i))
        {
            for(int j=col+1;j<=M;j+=j&(-j))
            {
                tree[i][j]+=add;
            }
        }
    }
    
    int sumRegion(int row1, int col1, int row2, int col2) 
    {
        if(N==0||M==0)
        {
            return 0;
        }
        return sum(row2,col2)+sum(row1-1,col1-1)-sum(row1-1,col2)-sum(row2,col1-1);
    }
};

你可能感兴趣的:(数据结构(C++实现),算法,c++,数据结构)