考前复习——树状数组

树状数组是一种支持 单点修改 和 区间查询 的,代码量小的数据结构。

什么是「单点修改」和「区间查询」?

假设有这样一道题:

已知一个数列 a,你需要进行下面两种操作:

给定 x, y,将 a[x] 自增 y。
给定 l, r,求解 a[l...r] 的和。
其中第一种操作就是「单点修改」,第二种操作就是「区间查询」。

点击查看代码
int n;
int a[N],c[N];//a[]:原数组  c[]:树状数组 

inline int lowbit(int x)//返回最低位1 即树状数组c[]所代表的区间长度 
{
	return x&(-x);
}

int query(int u)
{
	//a[1..u]之和 
	int ans=0;
	for(int i=u;i>0;i-=lowbit(i))
		ans+=c[i];
	return ans;//请务必记得这个!!! 
}

inline int interval(int l,int r)//区间和 
{
	return query(r)-query(l-1);
}

void single_update(int u,int w)
{
	//单点修改:将u位置的值加上w 
	//修改被a[u]影响的所有的c[] 
	for(int i=0;i<=u;i+=lowbit(i))
		c[i]+=w;
}

int main()
{
	cin>>n;//输入节点数
	for(int i=1;i<=n;i++)
	{
		cin>>a[i];
		single_update(i,a[i]);//制作c[] 
	} 
    cout<<interval(1,n)<<endl;//输出1~n区间和
	return 0;
}

若为矩阵 有如下代码

点击查看代码
void add(int x, int y, int v) {
    for (int i = x; i <= n ;i += lowbit(i)) {
        for (int j = y; j <= m; j += lowbit(j)) {
            // 注意这里必须得建循环变量,不能像一维数组一样直接 while (x <= n) 了
            c[i][j] += v;
        }
    }
}

int sum(int x, int y) {
  int res = 0;
  for (int i = x; i > 0; i -= lowbit(i)) {
      for (int j = y; j > 0; j -= lowbit(j)) {
          res += c[i][j];
      }
  }
  return res;
}

int ask(int x1, int y1, int x2, int y2) {
    // 查询子矩阵和
    return sum(x2, y2) - sum(x2, y1 - 1) - sum(x1 - 1, y2) + sum(x1 - 1, y1 - 1);
}
posted @ 2023-06-13 17:30  pig_pig  阅读(16)  评论(0)    收藏  举报