当前位置: 首页 > news >正文

【打卡】树状数组的操作

#define MAXN 1000 int n;                  // 数组实际长度
int array[MAXN];        // 原始数组(下标从0开始)
int tree[MAXN];         // 树状数组(下标从1开始)
int p[MAXN];            // 前缀和数组(下标从1开始)int lowbit(int x) {return x & (-x);
}
  • lowbit 函数:返回 x 的最低位 1 所代表的数值。例如,lowbit(6) 返回 2(因为 6 的二进制是110,最低位 1 对应的值是10即 2)。这个函数是树状数组的核心工具,用于确定节点管辖范围和父子关系。
  • tree 数组:树状数组的核心存储结构,tree[i] 存储区间 [i-lowbit(i)+1, i] 的元素和。
void init() {for (int i = 1; i <= n; i++) {tree[i] = array[i - 1];  // 注意array下标从0开始for (int j = i - 1; j > i - lowbit(i); j -= lowbit(j)) {tree[i] += tree[j];}}
}
  • 初始化逻辑
    1. 先将每个节点初始化为对应原始数组的值(tree[i] = array[i-1])。
    2. 再累加前面的节点值:对于节点i,需要加上所有管辖范围与i有重叠的前驱节点(即j > i - lowbit(i)的节点)。
  • 时间复杂度:O (n log n),适用于静态初始化。若需更高效的 O (n) 初始化,可改用差分法。
void update(int index, int value) {while (index <= n) {tree[index] += value;index += lowbit(index);}
}
  • 功能:将原始数组中第index个元素增加value,并更新树状数组。
  • 更新路径:从当前节点开始,不断向上找到父节点(通过index += lowbit(index)),直到超出数组范围。
  • 示例:若更新index=3,则更新路径为:3 → 4 → 8 → ...,直到index > n
int q(int index) {int sum = 0;while (index > 0) {sum += tree[index];index -= lowbit(index);}return sum;
}
  • 功能:计算原始数组前index个元素的和(即array[0] + array[1] + ... + array[index-1])。
  • 查询路径:从当前节点开始,不断向左上方找到 “管辖前缀” 的节点(通过index -= lowbit(index)),直到index=0
  • 示例:查询index=7的前缀和时,路径为:7 → 6 → 4 → 0,累加tree[7] + tree[6] + tree[4]
int main() {scanf("%d", &n);for (int i = 0; i < n; i++) {scanf("%d", &array[i]);}init();  // 初始化树状数组// 输出树状数组的内容for (int i = 1; i <= n; i++) {printf("%d ", tree[i]);}printf("\n");// 计算并输出前缀和数组for (int i = 1; i <= n; i++) {p[i] = q(i);printf("%d ", p[i]);}printf("\n");return 0;
}
  1. 输入处理:读取数组长度nn个元素。
  2. 初始化树状数组:调用init()构建树状数组。
  3. 输出树状数组:直接打印tree数组,展示每个节点存储的值。
  4. 计算前缀和:通过q()函数计算每个位置的前缀和,并存储在p数组中输出。

体会:

通过完成树状数组的代码实现,我对这一数据结构有了更深入的理解。最初理解 lowbit 函数的作用时较为抽象,但通过调试和示例推导,逐渐明白它如何划分区间、构建树状结构。初始化函数中,通过循环累加前驱节点值的逻辑,让我直观看到每个节点如何聚合子区间的和,这比单纯记忆公式更有助于掌握原理。

单点更新和前缀查询的递归式路径遍历(通过加减 lowbit)是树状数组的核心技巧,这种 “自底向上” 和 “自顶向下” 的操作模式,将 O (n) 的时间复杂度优化到 O (log n),体现了算法设计的精妙。在主函数测试中,通过输出 tree 数组和前缀和数组,验证了逻辑的正确性,尤其是看到 tree 数组中各节点存储的区间和与理论推导一致时,成就感较强。

不过,代码中初始化的 O (n log n) 复杂度仍有优化空间,后续可以尝试差分法实现 O (n) 初始化。此外,树状数组在逆序对、区间更新等场景的扩展应用,还需要进一步实践。这次实现不仅巩固了理论知识,也让我体会到算法与代码结合时,细节处理(如下标转换)的重要性,对提升逻辑思维和问题解决能力很有帮助。

相关文章:

  • Linux系统移植①:uboot概念
  • WSL 基础命令
  • DeepSeek+白果AI论文:开启答辩PPT生成的「智能双引擎」时代
  • AI大模型(三)openAI大模型应用
  • 《100天精通Python——基础篇 2025 第20天:Thread类与线程同步机制详解》
  • 『uniapp』uni-share 分享功能 使用例子(保姆级图文)
  • java线程中断的艺术
  • 绿色屋顶和墙壁行业2025数据分析报告
  • 【批量文件夹重命名】如何按照Excel表格对应的关系,批量一对一的重命名文件夹,文件夹按照对应映射关系一对一改名
  • 打破产品思维--启示录:打造用户喜欢的产品--实战6
  • RocketMq的消息类型及代码案例
  • [C++面试] 基础题 11~20
  • 归一化 超全总结!!
  • 编译rk3568的buildroot不起作用
  • pvlib(太阳轨迹)
  • 基于CodeBuddy实现本地网速的实时浏览小工具
  • 算法题(154):合并果子
  • [NOIP 2003 普及组] 麦森数 Java
  • 由浮点数的位级表示判断大小关系
  • 电子电路:为什么导体中的电子数量能够始终保持不变?
  • 做阿里巴巴网站图片大全/上海今天刚刚发生的新闻
  • 六盘水市网站建设/网站开发用什么语言
  • 企业网站建设代理加盟/点击精灵seo
  • 网站图片如何做超链接/优化设计五年级下册语文答案
  • 网站开发php制作/正规网络公司关键词排名优化
  • 企业营销型网站建设图片/seo实战密码电子书