树状数组(C++)
模板化的数据结构,必背。
树状数组的核心思想在于,两两相邻的相加,然后汇总到上方,再继续两两相邻相加。但是要注意的是,上层的两两相邻并不是指在数组位置中的相邻,而是因为他俩所包含的区间相邻。
举例如下:
第二层: 10 10=3+7 第一层: 3 7 3=1+2, 7=3+4 原始数据: 1 2 3 4
实际上,你确实可以把他看做一个倒着来的杨辉三角求解过程,只不过杨辉三角是为了继续拓展三角的下端,而树状数组是要把数据汇总起来。
lowbit函数:获取上一层的位置
很多人都不理解什么是lowbit函数,为什么能这样。实际上我个人认为,目前阶段(单指OI竞赛)没太多必要去真正理解lowbit背后的思想,只需要记得他会在数组中自己找一个合适的位置帮你存储对应的数据就可以了。
return x & -x;
Add函数:修改某个数字,并修改树上所有信息
通过lowbit函数,将修改的值一层一层的加上去。函数中,x为需要修改的位置(此处修改为加法),v则是增加的值。
void add(int x, int v){ for(int i=x; i<=n; i+=lowbit(i)) //i+=lowbit(i)是为了寻找下一个位置 tr[i]+=v;//修改区间的总和 }
query函数:查询对应区间
得到对应区间的总值,但是是前缀和的形式。如果要查询其中一个区间的和,则需要后区间减去前区间即可。
int query(int x){ int res = 0; for(int i=x; i; i -= lowbit(i)) //此处的i-=lowbit(i)就相当于一层一层向下找对应区间 res += tr[i]; return res; } int rangeQuery(int x, int y){ return query(y) - query(x-1); }
以上代码总结起来就可以得到以下样例代码:
class TreeArray{ private: vector<int> tr; int n; public: void init(vector<int> g){ for(int i=1; i<=g.size(); i++) //由于树状数组需要从1位开始,所以vector<int> g要再输入前先push_back([任意数字]); 这样就能让数据从[1]位开始,而此处tr.push_back(0);是为了直接填充对应量的数据防止读取错误。 tr.push_back(0); n = tr.size(); for(int i=1; i<n; i++) add(i, g[i]); } int lowbit(int x){ return x & -x; } void add(int x, int v){ for(int i=x; i<=n; i += lowbit(i)) tr[i]+=v; } int query(int x){ int res = 0; for(int i=x; i; i -= lowbit(i)) res += tr[i]; return res; } int rangeQuery(int x, int y){ return query(y) - query(x-1); } };
是的,你可以把他做成一个Snippet,然后直接调用一整个树状数组。会和线段树一起放出对应的snippet。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现