1. 题目背景与核心需求
这道来自《信息学奥赛一本通》P1535的数列操作题,是信息学竞赛中典型的树状数组(BIT)入门练习题。题目要求实现两种基本操作:单点修改(将某个位置的数值增加指定值)和区间查询(求某个区间内所有数的和)。这类问题在ACM/ICPC、NOIP等编程竞赛中频繁出现,也是理解更高级数据结构(如线段树)的重要基础。
在实际比赛中,这类问题的典型输入规模是数列长度N和操作次数M都在1e5量级,这意味着暴力解法(O(MN)时间复杂度)必然超时。而使用树状数组可以将两种操作的时间复杂度都优化到O(logN),完美满足竞赛要求。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 树状数组原理深度解析
2.1 二进制索引的巧妙设计
树状数组的核心思想是利用二进制表示中最低位1的位置来构建索引结构。具体来说,对于下标i,其管理的区间长度为lowbit(i) = i & -i(即保留i的二进制表示中最右边的1及其后的0)。例如:
- i = 6 (二进制110) → lowbit = 2 (二进制10)
- i = 8 (二进制1000) → lowbit = 8
这种设计使得更新和查询操作都只需要沿着二进制位的路径进行,保证了O(logN)的时间复杂度。以下是关键操作的数学表达:
单点更新(位置i增加v):
cpp复制void update(int i, int v) {
while (i <= n) {
tree[i] += v;
i += lowbit(i);
}
}
前缀和查询(前i项的和):
cpp复制int query(int i) {
int res = 0;
while (i > 0) {
res += tree[i];
i -= lowbit(i);
}
return res;
}
2.2 与线段树的对比分析
虽然线段树也能解决这类问题,但树状数组在实现上有明显优势:
| 特性 | 树状数组 | 线段树 |
|---|
