考前复习——树状数组

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

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

假设有这样一道题:

已知一个数列 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 @   pig_pig  阅读(8)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示