树状数组(Fenwick Tree)主要解决?
考点:树状数组解决的问题(A1)。
解析:树状数组解决单点修改 + 前缀查询(进而区间和),、代码极短(两个函数)。✅ 正确
排除法:无(判断题)。混淆点:区间最值不可差分,树状数组做不了。
关联 · 树状数组的限制(A5):能力边界。
的定义是?
考点:lowbit 的定义(A2)。
解析:lowbit(x) = x 二进制最低位 1 及其后面的 0——如 lowbit(6) = 2()。✅ 正确
排除法:无(判断题)。混淆点:不是最高位 1、不是位数。
关联 · lowbit 的计算(B1):代码实现。
树状数组中节点 负责维护的区间是?
考点:树状数组的结构(A3)。
解析:节点 管 ——以 结尾、长 lowbit(i) 的区间。✅ 正确
排除法:无(判断题)。混淆点:不是 (那是前缀和的含义)。
关联 · 节点管的区间(B3):结构细节。
树状数组与线段树的正确对比是?
考点:与线段树的对比(A4)。
解析:树状数组代码短、常数小,功能受限;线段树全面。✅ 正确
排除法:无(判断题)。混淆点:两者是互补关系非包含关系。
关联 · 选择矩阵(G2):怎么选。
判断题:树状数组只支持"可差分"的操作(如区间和 = 前缀和之差)——区间最值不可差分,不能用树状数组做。
考点:树状数组的限制(A5)。
解析:只支持可差分操作——区间和 = 前缀差;最值不可差分,做不了。✅ 正确
排除法:无(判断题)。混淆点:可差分性 = 能写成"前缀函数之差"。
关联 · 可差分操作的判定(D6):判定方法。
判断题:树状数组必须下标 1 起——因为 lowbit 运算依赖下标,0 下标会死循环。
考点:下标 1 起(A6)。
解析:下标必须 1 起——lowbit(0) = 0,0 下标死循环。✅ 正确
排除法:无(判断题)。混淆点:这是树状数组的头号实现纪律(H2/P2)。
关联 · 下标 0 起错误(H2):错误示范。
lowbit 的代码实现是?
考点:lowbit 的计算(B1)。
解析:x & (-x)——补码技巧一步到位。✅ 正确
排除法:无(判断题)。混淆点:x & (x-1) 是"去掉最低位 1"(另一个函数)。
关联 · lowbit 写错(H1):易混函数。
判断题: 恒为 2 的幂,且 恰好去掉最低位的 1。
考点:lowbit 的性质(B2)。
解析:lowbit(x) 恒为 2 的幂; 去掉最低位 1。✅ 正确
排除法:无(判断题)。混淆点:这两条性质支撑 add/sum 的跳转正确性。
关联 · lowbit 性质(I5):代码版。
,节点 6 维护的区间是?
考点:节点管的区间(B3)。
解析:lowbit(6) = 2 → 节点 6 管 。✅ 正确
排除法:无(判断题)。混淆点:左端点 = 。
关联 · 树状数组的结构(A3):实例。
的 lowbit 序列是?
考点:区间长度规律(B4)。
解析: 的 lowbit:1 2 1 4 1 2 1 8。✅ 正确
排除法:无(判断题)。混淆点:奇数恒 1、2 的幂是自身。
关联 · lowbit 序列(I2):代码版。
判断题:树状数组按 lowbit 形成层次——节点 8 管 、节点 4 管 、节点 6 管 ——区间层层覆盖不重不漏。
考点:树的层次结构(B5)。
解析:区间层层覆盖不重不漏——8 管 、4 管 、6 管 。✅ 正确
排除法:无(判断题)。混淆点:覆盖性 = 前缀查询正确的根基。
关联 · 结构综合(B7):二进制分解。
lowbit 的经典应用是?
考点:lowbit 的应用(B6)。
解析:树状数组跳转——add 上跳、sum 下跳。✅ 正确
排除法:无(判断题)。混淆点:排序/哈希/图遍历不用 lowbit。
关联 · 修改与查询的方向(C7):跳转方向。
判断题:树状数组用"二进制分解"把前缀 拆成 段——每段对应一个节点,这是它 的根源。
考点:结构综合(B7)。
解析:前缀 拆成 段(每段一个节点)—— 的根源。✅ 正确
排除法:无(判断题)。混淆点:段数 = x 二进制中 1 的个数。
关联 · 前缀查询复杂度(C6):复杂度来源。
树状数组单点加 add(i, v) 的循环是?
考点:add 单点加(C1)。
解析:for (; i <= n; i += lowbit(i)) c[i] += v——往上跳更新所有覆盖 i 的节点。✅ 正确
排除法:无(判断题)。混淆点:方向是 +lowbit(往上)。
关联 · add 的路径(C2):路径实例。
时,add(3, v) 更新哪些节点?
考点:add 的路径(C2)。
解析:add(3) → 3、4、8(3+1=4、4+4=8、8+8=16 > 8 停)。✅ 正确
排除法:无(判断题)。混淆点:路径上每个节点都含位置 3。
关联 · add 路径输出(J1):代码版。
树状数组前缀查询 sum(x) 的循环是?
考点:sum 前缀查询(C3)。
解析:for (; x > 0; x -= lowbit(x)) s += c[x]——往下跳收集覆盖段。✅ 正确
排除法:无(判断题)。混淆点:方向是 -lowbit(往下)。
关联 · sum 的路径(C4):路径实例。
时,sum(6) 累加哪些节点?
考点:sum 的路径(C4)。
解析:sum(6) → 6、4(6-2=4、4-4=0 停)。✅ 正确
排除法:无(判断题)。混淆点:收集的段 与 恰好拼成 。
关联 · sum 路径输出(J2):代码版。
树状数组单点修改的复杂度是?
考点:单点修改复杂度(C5)。
解析:——每跳 lowbit 至少翻倍。✅ 正确
排除法:无(判断题)。混淆点:不是 (路径有多层)。
关联 · add 的路径(C2):路径长度。
树状数组前缀查询的复杂度是?
考点:前缀查询复杂度(C6)。
解析:——二进制分解的段数。✅ 正确
排除法:无(判断题)。混淆点:段数 ≤ 二进制位数。
关联 · 结构综合(B7):分解视角。
判断题:add 沿"往上跳"(i += lowbit)更新所有包含它的节点;sum 沿"往下跳"(i -= lowbit)收集覆盖前缀的节点——方向相反。
考点:修改与查询的方向(C7)。
解析:add 上跳(i += lowbit)、sum 下跳(i -= lowbit)——方向相反。✅ 正确
排除法:无(判断题)。混淆点:方向记反 = 死循环或漏节点。
关联 · add 与 sum 填空(J5):方向填空。
树状数组求区间 的和的公式是?
考点:区间和(D1)。
解析: 和 = sum(r) - sum(l-1)——前缀差。✅ 正确
排除法:无(判断题)。混淆点:不是 sum(r) - sum(l)(会漏掉 )。
关联 · 区间和输出(K1):代码版。
用差分 + 树状数组实现"区间加、单点查"的做法是?
考点:差分实现区间加单点查(D2)。
解析:对差分数组建树——区间加变成 diff[l] += v、diff[r+1] -= v 两个单点修改。✅ 正确
排除法:无(判断题)。混淆点:单点查 = 差分前缀和。
关联 · 差分区间加单点查(K2):代码版。
判断题:区间加 + 区间查需要两个树状数组(一个维护 diff、一个维护 i×diff)——利用前缀和公式拆解。
考点:差分实现区间加区间查(D3)。
解析:区间加 + 区间查需要两个树状数组(diff 与 i×diff)。✅ 正确
排除法:无(判断题)。混淆点:前缀和公式拆解出两项。
关联 · 区间操作综合(D7):全谱系。
树状数组求逆序对的思路是?
考点:求逆序对(D4)。
解析:从左到右插入(值作下标),统计已插入中大于 a[i] 的个数。✅ 正确
排除法:无(判断题)。混淆点:大于 a[i] 的个数 = 已插总数 - 前缀和。
关联 · 逆序对输出(K4):代码版。
判断题:值域很大(如 )时树状数组下标开不下——先离散化把值映射到排名再建树。
考点:树状数组与离散化(D5)。
解析:值域 开不下下标——先离散化到排名。✅ 正确
排除法:无(判断题)。混淆点:离散化保持大小关系即可(逆序对只关心序)。
关联 · 离散化加树状数组(K5):代码版。
下列哪个操作能用树状数组(含差分技巧)实现?
考点:可差分操作的判定(D6)。
解析:区间和/加/逆序对可差分——最值、众数不可。✅ 正确
排除法:无(判断题)。混淆点:判定标准 = 能否写成"前缀函数之差"。
关联 · 树状数组的限制(A5):判定依据。
判断题:树状数组通过"差分 + 前缀和分解"能覆盖大部分区间修改查询问题——但最值类操作仍需要线段树。
考点:区间操作综合(D7)。
解析:差分 + 前缀分解覆盖大部分区间修改查询;最值仍需线段树。✅ 正确
排除法:无(判断题)。混淆点:两结构的边界在"可差分性"。
关联 · 差分实现区间加区间查(D3):能力上限。
ST 表(Sparse Table)解决什么问题?
考点:ST 表解决的问题(E1)。
解析:静态 RMQ——建表后 查询、不支持修改。✅ 正确
排除法:无(判断题)。混淆点:静态是核心约束。
关联 · 与线段树对比(E6):动静对比。
ST 表的倍增思想是?
考点:倍增思想(E2)。
解析:预处理所有 长区间的最值,查询用两个 2 的幂区间覆盖。✅ 正确
排除法:无(判断题)。混淆点:倍增 = 状态按 2 的幂展开(与快速幂同源)。
关联 · st[i][j] 的含义(E3):状态定义。
表示?
考点:st[i][j] 的含义(E3)。
解析:st[i][j] = 从 开始、长 的区间最值。✅ 正确
排除法:无(判断题)。混淆点:不是 的和。
关联 · 建表递推(F1):状态转移。
ST 表建表的时间复杂度是?
考点:建表复杂度(E4)。
解析:—— 个状态各 。✅ 正确
排除法:无(判断题)。混淆点:比线段树建树贵,换查询 。
关联 · 复杂度对比(M5):建与查的权衡。
ST 表单次查询的复杂度是?
考点:查询复杂度(E5)。
解析:——两段区间取最值。✅ 正确
排除法:无(判断题)。混淆点:是 ST 表对线段树的核心优势。
关联 · 查询两段覆盖(F2):两段技巧。
ST 表与线段树的正确对比是?
考点:与线段树对比(E6)。
解析:ST 表查询 但不能改;线段树动态。✅ 正确
排除法:无(判断题)。混淆点:静态 RMQ 无脑 ST 表。
关联 · 选择矩阵(G2):选型。
ST 表建表的递推公式是?
考点:建表递推(F1)。
解析:——两半合并。✅ 正确
排除法:无(判断题)。混淆点:第二段起点 (前一半长度)。
关联 · 建表输出(L1):代码版。
判断题:查询 取 ,用 与 两段重叠覆盖整个区间——重叠无害(最值幂等)。
考点:查询两段覆盖(F2)。
解析:,两段 与 重叠覆盖——最值幂等无害。✅ 正确
排除法:无(判断题)。混淆点:重叠是允许的(max(max) = max)。
关联 · 查询公式(F5):公式化。
判断题:log 值预处理 lg[i] = lg[i/2] + 1——查询时 取到 。
考点:log 预处理(F3)。
解析:lg[i] = lg[i/2] + 1—— 预处理、查询 取 k。✅ 正确
排除法:无(判断题)。混淆点:不预处理用 log2() 也行,预处理更稳。
关联 · log 预处理(L3):代码版。
查询 (长度 5)时 取?
考点:区间长度选取(F4)。
解析:长度 5 → (两段长 4)。✅ 正确
排除法:无(判断题)。混淆点:k 取"不超过长度的最大 2 的幂指数"。
关联 · 查询两段覆盖(F2):k 的选取。
ST 表查询 的公式是?
考点:查询公式(F5)。
解析:。✅ 正确
排除法:无(判断题)。混淆点:第二段起点 (+1 别漏)。
关联 · ST 表查询段选取错(H3):易错点。
判断题:ST 表实现三件套 = 建表递推(倍增合并)+ log 预处理 + 查询两段覆盖——缺一不可。
考点:实现综合(F6)。
解析:三件套 = 建表递推 + log 预处理 + 查询两段覆盖。✅ 正确
排除法:无(判断题)。混淆点:三件套是 ST 表的完整模板。
关联 · ST 综合(L6):代码版。
线段树、树状数组、ST 表的总表是?
考点:三结构总表(G1)。
解析:线段树全面 、树状数组轻量可差分、ST 表静态 。✅ 正确
排除法:无(判断题)。混淆点:功能与速度的三角权衡。
关联 · 综合对比(G5):权衡总结。
静态 RMQ(不修改)最佳选择是?
考点:选择矩阵(G2)。
解析:静态 RMQ → ST 表()。✅ 正确
排除法:无(判断题)。混淆点:树状数组做不了最值,直接排除。
关联 · 三结构选择(M1):代码版。
判断题:树状数组应用总表——单点改区间查、区间改单点查(差分)、区间改区间查(双树状数组)、逆序对、第 k 小(倍增思想)。
考点:树状数组应用总表(G3)。
解析:单点改区间查、区间改单点查、区间改区间查(双树)、逆序对、第 k 小。✅ 正确
排除法:无(判断题)。混淆点:第 k 小用二分 + 前缀和。
关联 · 第 k 小思想(N3):代码版。
判断题:ST 表应用总表——静态 RMQ、区间 gcd(幂等运算皆可)、LCA 预处理思想——一切幂等且静态的区间查询。
考点:ST 表应用总表(G4)。
解析:一切幂等且静态的区间查询——RMQ、gcd、LCA 预处理。✅ 正确
排除法:无(判断题)。混淆点:幂等 = f(x,x) = x(重叠无害)。
关联 · ST 表解决的问题(E1):用途外延。
判断题:三结构按"功能 × 速度"权衡——ST 表最快最受限、树状数组最轻量、线段树最全面。
考点:综合对比(G5)。
解析:ST 表最快最受限、树状数组最轻量、线段树最全面。✅ 正确
排除法:无(判断题)。混淆点:三角定位是选型直觉。
关联 · 三结构总表(G1):权衡表。
需要"单点修改 + 区间和查询",代码要短,选?
考点:选择综合(G6)。
解析:单点改 + 区间和、代码短 → 树状数组。✅ 正确
排除法:无(判断题)。混淆点:线段树可行但代码长。
关联 · 线段树与树状数组代码量(M2):代码量对比。
判断题:lowbit 写成 x & (x - 1) 是"去掉最低位 1"(不是 lowbit)——循环会跳错。
考点:lowbit 写错(H1)。
解析:x & (x-1) 是"去掉最低位 1"——与 lowbit 是不同函数,混用跳转错乱。✅ 正确
排除法:无(判断题)。混淆点:两个位运算函数形近。
关联 · lowbit 写成 0(P1):错误示范。
判断题:树状数组下标 0 起会死循环——0 + lowbit(0) = 0 永远跳不上去。
考点:下标 0 起错误(H2)。
解析:lowbit(0) = 0 → i += 0 死循环。✅ 正确
排除法:无(判断题)。混淆点:下标 1 起是硬约束。
关联 · 下标 0 起(P2):错误示范。
判断题:ST 表查询的两段是 与 ——第二段起点写成 会漏掉 r。
考点:ST 表查询段选取错(H3)。
解析:第二段起点 ——漏 +1 覆盖错位(P3 实测漏掉端点)。✅ 正确
排除法:无(判断题)。混淆点:+1 是边界纪律。
关联 · ST 查询越界(P3):错误示范。
判断题:区间加 [l,r] 的差分是 diff[l] += v、diff[r+1] -= v——两处符号写反会导致整个区间错。
考点:差分方向错(H4)。
解析:区间加 = diff[l] += v、diff[r+1] -= v——符号反了整个区间错。✅ 正确
排除法:无(判断题)。混淆点:l 加 r+1 减的口诀别反。
关联 · 差分方向反(P4):错误示范。
判断题:以下结论全部正确——"lowbit 用 x&-x;add 往上跳、sum 往下跳;下标必须 1 起;ST 表查询两段重叠覆盖;差分区间加是 l 加 r+1 减"。
考点:综合判断(H5)。
解析:五结论全对——lowbit x&-x、add 上跳 sum 下跳、下标 1 起、ST 两段重叠、差分 l 加 r+1 减。✅ 正确
排除法:无(判断题)。混淆点:本章核心模板要点收官自查。
关联 · 本章全部核心结论:收官综合判断题。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int x = 6; // 110 的二进制 05 cout << (x & (-x)); // lowbit 06 return 0; 07}
单选题:程序输出是?
考点:lowbit 输出(I1)。
解析: → lowbit = 2。正确答案 A。
实现要点:x & (-x) 一步取最低位 1 及其后 0。手算:110 & 010 = 010。
排除法:B 是去掉 1 后的值;C/D 无依据。
关联 · lowbit 的计算(B1):概念题代码化。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 for (int i = 1; i <= 8; i++) cout << (i & (-i)) << " "; 05 return 0; 06}
单选题:程序输出是?
考点:lowbit 序列(I2)。
解析:1~8 的 lowbit = 1 2 1 4 1 2 1 8。正确答案 A。
实现要点:奇数恒 1、2 的幂是自身。手算:逐个 x&-x。
排除法:B/C/D 无依据。
关联 · 区间长度规律(B4):概念题代码化。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int i = 6; 05 int lb = i & (-i); 06 cout << i - lb + 1 << " " << i; // 节点 6 管的区间 [左端点, 右端点] 07 return 0; 08}
单选题:程序输出是?
考点:节点管区间(I3)。
解析:。正确答案 A。
实现要点:节点 i 管 。手算:套公式。
排除法:B 是前缀;C 是单点;D 无依据。
关联 · 节点管的区间(B3):概念题代码化。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int x = 12; 05 cout << ______; // lowbit(12) = 4 06 return 0; 07}
单选题:横线处应填入?(使输出为 4)
考点:lowbit 填空(I4)。
解析:x & (-x)——12 = 1100 → 4。正确答案 A。
实现要点:补码取最低位 1。手算:1100 & 0100 = 0100。
排除法:B 是去 1;C 是或;D 无依据。
关联 · lowbit 输出(I1):填空版。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int x = 6; // 110 05 int y = x - (x & (-x)); // 去掉最低位 1 06 cout << y; // 100 = 4 07 return 0; 08}
单选题:程序输出是?
考点:lowbit 性质(I5)。
解析:6 - lowbit(6) = 4(110 → 100)。正确答案 A。
实现要点:减 lowbit = 去掉最低位 1。手算:110 - 010 = 100。
排除法:B 是 lowbit 本身;C/D 无依据。
关联 · lowbit 的性质(B2):概念题代码化。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int x = 20; // 10100 05 int cnt = 0; 06 while (x) { x -= (x & (-x)); cnt++; } // 数二进制中 1 的个数 07 cout << cnt; 08 return 0; 09}
单选题:程序输出是?(20 = 10100 有 2 个 1)
考点:lowbit 综合(I6)。
解析:20 = 10100 有两个 1 → 2。正确答案 A。
实现要点:反复减 lowbit 数 1 的个数。手算:10100 → 10000 → 0。
排除法:B/C/D 无依据。
关联 · lowbit 的性质(B2):应用版。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int i = 3, n = 8; 05 while (i <= n) { 06 cout << i << " "; 07 i += (i & (-i)); // add 的跳转 08 } 09 return 0; 10}
单选题:程序输出是?(add(3) 更新的节点路径)
考点:add 路径输出(J1)。
解析:3 → 4 → 8(上跳)。正确答案 A。
实现要点:add 的 i += lowbit(i) 上跳。手算:3+1=4、4+4=8、8+8>8 停。
排除法:B 是 sum 路径;C 是下跳;D 无依据。
关联 · add 的路径(C2):概念题代码化。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int x = 6; 05 while (x > 0) { 06 cout << x << " "; 07 x -= (x & (-x)); // sum 的跳转 08 } 09 return 0; 10}
单选题:程序输出是?(sum(6) 累加的节点路径)
考点:sum 路径输出(J2)。
解析:6 → 4(下跳)。正确答案 A。
实现要点:sum 的 i -= lowbit(i) 下跳。手算:6-2=4、4-4=0 停。
排除法:B/C/D 无依据。
关联 · sum 的路径(C4):概念题代码化。
01#include <bits/stdc++.h> 02using namespace std; 03int a[9] = {0, 1, 3, 5, 7, 9, 11, 13, 15}; 04int c[9] = {0}; 05int main() { 06 for (int i = 1; i <= 8; i++) { // 建树:逐点 add 07 int j = i; 08 while (j <= 8) { c[j] += a[i]; j += (j & (-j)); } 09 } 10 int x = 6, s = 0; 11 while (x > 0) { s += c[x]; x -= (x & (-x)); } // sum(6) 12 cout << s; 13 return 0; 14}
单选题:程序输出是?(前 6 项和 = 1+3+5+7+9+11)
考点:前缀和输出(J3)。
解析:sum(6) = c[6]+c[4] = 20+16 = 36。正确答案 A。
实现要点:建树逐点 add + 前缀下跳求和。手算:1+3+5+7+9+11。
排除法:B 是前 6 个奇数误算;C 是总和;D 无依据。
关联 · sum 前缀查询(C3):概念题代码化。
01#include <bits/stdc++.h> 02using namespace std; 03int a[9] = {0, 1, 3, 5, 7, 9, 11, 13, 15}; 04int c[9] = {0}; 05int main() { 06 for (int i = 1; i <= 8; i++) { 07 int j = i; 08 while (j <= 8) { c[j] += a[i]; j += (j & (-j)); } 09 } 10 int p = 3, v = 2; // a[3] += 2 11 while (p <= 8) { c[p] += v; p += (p & (-p)); } 12 int x = 6, s = 0; 13 while (x > 0) { s += c[x]; x -= (x & (-x)); } 14 cout << s; 15 return 0; 16}
单选题:程序输出是?(a[3] 加 2 后前 6 项和 = 36 + 2)
考点:单点修改输出(J4)。
解析:a[3] += 2 → sum(6) = 38。正确答案 A。
实现要点:单点修改 = add 上跳更新。手算:36 + 2。
排除法:B 是改前;C/D 无依据。
关联 · add 单点加(C1):概念题代码化。
01#include <bits/stdc++.h> 02using namespace std; 03int c[9] = {0, 1, 4, 5, 16, 9, 20, 13, 64}; 04void add(int i, int v) { 05 while (i <= 8) { c[i] += v; i += ______; } // lowbit 上跳 06} 07int sum(int x) { 08 int s = 0; 09 while (x > 0) { s += c[x]; x -= ______; } // lowbit 下跳 10 return s; 11} 12int main() { 13 add(5, 10); // a[5] += 10 14 cout << sum(5); 15 return 0; 16}
单选题:两处横线应填入?(使输出为 35——add(5) 更新 c[5]、c[6]、c[8],sum(5) = c[5]+c[4] = 19+16)
考点:add 与 sum 填空(J5)。
解析:两处 i & (-i) 与 x & (-x);add(5) 更新 c[5]、c[6]、c[8],sum(5) = 19+16 = 35。正确答案 A。
实现要点:add 上跳、sum 下跳的 lowbit。手算:5→6→8;5→4。
排除法:B/C/D 无依据。
关联 · 修改与查询的方向(C7):填空版。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 // 建树 + 两次修改 + 区间查询 05 int a[9] = {0, 2, 4, 6, 8, 10, 12, 14, 16}; 06 int c[9] = {0}; 07 for (int i = 1; i <= 8; i++) { 08 int j = i; 09 while (j <= 8) { c[j] += a[i]; j += (j & (-j)); } 10 } 11 for (int p : {2, 5}) { // a[2] += 1、a[5] += 1 12 int j = p; 13 while (j <= 8) { c[j] += 1; j += (j & (-j)); } 14 } 15 auto sum = [&](int x) { int s = 0; while (x > 0) { s += c[x]; x -= (x & (-x)); } return s; }; 16 cout << sum(6) - sum(2); // [3,6] 的和 17 return 0; 18}
单选题:程序输出是?(原 [3,6] = 6+8+10+12 = 36,a[5] 在区间内 +1 → 37)
考点:综合(J6)。
解析:a[2]、a[5] 各 +1 → [3,6] 和 = 36+1 = 37(a[5] 在区间内)。正确答案 A。
实现要点:多次修改 + 区间差查询。手算:sum(6)-sum(2)。
排除法:B 忘了 a[5];C/D 无依据。
关联 · 区间和(D1):综合版。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int a[9] = {0, 1, 3, 5, 7, 9, 11, 13, 15}; 05 int c[9] = {0}; 06 for (int i = 1; i <= 8; i++) { 07 int j = i; 08 while (j <= 8) { c[j] += a[i]; j += (j & (-j)); } 09 } 10 auto sum = [&](int x) { int s = 0; while (x > 0) { s += c[x]; x -= (x & (-x)); } return s; }; 11 cout << sum(6) - sum(2); // [3,6] 的和 = 36 - 4 12 return 0; 13}
单选题:程序输出是?([3,6] = 5+7+9+11)
考点:区间和输出(K1)。
解析:[3,6] = sum(6)-sum(2) = 36-4 = 32。正确答案 A。
实现要点:区间和 = 前缀差。手算:5+7+9+11。
排除法:B 是 sum(6);C/D 无依据。
关联 · 区间和(D1):概念题代码化。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int n = 5; 05 int diff[6] = {0, 1, 0, 0, 0, 0}; // 初始 a 全 1 的差分(a[i]=a[i-1]+diff[i]) 06 // 区间 [2,4] +3:diff[2] += 3、diff[5] -= 3 07 diff[2] += 3; diff[5] -= 3; 08 int x = 3, s = 0; // 查 a[3] = 前缀和 09 for (int i = 1; i <= x; i++) s += diff[i]; 10 cout << s; 11 return 0; 12}
单选题:程序输出是?(a[3] = 1 + 3 = 4)
考点:差分区间加单点查(K2)。
解析:diff = {0,1,0,0,0,0} 加 [2,4]+3 → diff[2]=4、diff[5]=-3;a[3] = 1+3+0 = 4。正确答案 A。
实现要点:差分前缀和还原单点。手算:a[3] = diff[1]+diff[2]+diff[3]。
排除法:B 忘了加 3;C/D 无依据。
关联 · 差分实现区间加单点查(D2):概念题代码化。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 // 区间加 + 区间查:双树状数组(此处直接模拟最终效果) 05 // 初始 {1,1,1,1,1},[1,3] +2、[3,5] +1 → {2,2,3,1,1}(注意 d 是"增量") 06 int a[6] = {0, 1, 1, 1, 1, 1}; 07 int d[7] = {0}; 08 d[1] += 2; d[4] -= 2; // [1,3] +2 09 d[3] += 1; d[6] -= 1; // [3,5] +1 10 for (int i = 1; i <= 5; i++) { a[i] = a[i - 1] + d[i]; cout << a[i] << " "; } 11 return 0; 12}
单选题:程序输出是?(差分前缀和还原后的数组)
考点:差分区间加还原(K3)。
解析:d[1]+=2、d[4]-=2、d[3]+=1、d[6]-=1 → 还原 {2,2,3,1,1}。正确答案 A。
实现要点:两次区间加叠加、前缀和还原。手算:逐位累加。
排除法:B 是初值;C/D 无依据。
关联 · 差分方向(H4):正向示范。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int a[4] = {3, 1, 4, 2}; 05 long long cnt = 0; 06 // 朴素模拟(树状数组加速版同理):统计前面大于 a[i] 的个数 07 for (int i = 0; i < 4; i++) 08 for (int j = 0; j < i; j++) 09 if (a[j] > a[i]) cnt++; 10 cout << cnt; 11 return 0; 12}
单选题:程序输出是?({3,1,4,2} 的逆序对)
考点:逆序对输出(K4)。
解析:{3,1,4,2} 逆序对 3。正确答案 A。
实现要点:树状数组版 = 插入 + 前缀差统计。手算:(3,1)(3,2)(4,2)。
排除法:B/C/D 无依据。
关联 · 求逆序对(D4):概念题代码化。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int a[4] = {100, 5, 99999, 50}; 05 int b[4]; 06 for (int i = 0; i < 4; i++) b[i] = a[i]; 07 sort(b, b + 4); // {5, 50, 100, 99999} 08 for (int i = 0; i < 4; i++) 09 cout << lower_bound(b, b + 4, a[i]) - b + 1 << " "; // 排名(1 起) 10 return 0; 11}
单选题:程序输出是?(离散化后的排名)
考点:离散化加树状数组(K5)。
解析:{100,5,99999,50} → 排名 {3,1,4,2}。正确答案 A。
实现要点:排序 + lower_bound 查排名。手算:排序 {5,50,100,99999}。
排除法:B 是原序;C/D 无依据。
关联 · 树状数组与离散化(D5):概念题代码化。
01#include <bits/stdc++.h> 02using namespace std; 03int c[9] = {0, 1, 4, 5, 16, 9, 20, 13, 64}; 04int sum(int x) { 05 int s = 0; 06 while (x > 0) { s += c[x]; x -= (x & (-x)); } 07 return s; 08} 09int main() { 10 int l = 3, r = 6; 11 cout << ______; // 区间和公式 12 return 0; 13}
单选题:横线处应填入?(使输出为 32)
考点:区间填空(K6)。
解析:sum(r) - sum(l - 1)。正确答案 A。
实现要点:区间和公式。手算:sum(6)-sum(2) = 36-4。
排除法:B 漏 a[l];C/D 无依据。
关联 · 区间和(D1):填空版。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 // 差分 + 树状数组:区间加 [2,6] +5 后查 [3,5] 的和 05 int a[9] = {0}; // 初始全 0 06 int d[10] = {0}; 07 d[2] += 5; d[7] -= 5; // [2,6] +5 08 for (int i = 1; i <= 8; i++) a[i] = a[i - 1] + d[i]; 09 int s = 0; 10 for (int i = 3; i <= 5; i++) s += a[i]; 11 cout << s; 12 return 0; 13}
单选题:程序输出是?([3,5] 内都是 +5 → 15)
考点:综合(K7)。
解析:[2,6]+5 后 [3,5] 和 = 15。正确答案 A。
实现要点:差分 + 前缀和综合。手算:区间内 3 个 × 5。
排除法:B/C/D 无依据。
关联 · 差分实现区间加单点查(D2):综合版。
01#include <bits/stdc++.h> 02using namespace std; 03int st[9][4]; 04int main() { 05 int a[9] = {0, 2, 4, 6, 8, 10, 12, 14, 16}; 06 for (int i = 1; i <= 8; i++) st[i][0] = a[i]; // j = 0 层 07 for (int j = 1; (1 << j) <= 8; j++) 08 for (int i = 1; i + (1 << j) - 1 <= 8; i++) 09 st[i][j] = max(st[i][j - 1], st[i + (1 << (j - 1))][j - 1]); 10 for (int j = 0; j <= 3; j++) cout << st[1][j] << " "; 11 return 0; 12}
单选题:程序输出是?(st[1][0..3]——从 1 开始长度 1/2/4/8 的最值)
考点:建表输出(L1)。
解析:st[1][0..3] = 2 4 8 16(长度 1/2/4/8 的最值)。正确答案 A。
实现要点:倍增合并递推。手算:max(2,4)=4、max(4,8)=8、max(8,16)=16。
排除法:B 是前缀和;C 是倒序;D 无依据。
关联 · 建表递推(F1):概念题代码化。
01#include <bits/stdc++.h> 02using namespace std; 03int st[9][4]; 04int main() { 05 int a[9] = {0, 2, 4, 6, 8, 10, 12, 14, 16}; 06 for (int i = 1; i <= 8; i++) st[i][0] = a[i]; 07 for (int j = 1; (1 << j) <= 8; j++) 08 for (int i = 1; i + (1 << j) - 1 <= 8; i++) 09 st[i][j] = max(st[i][j - 1], st[i + (1 << (j - 1))][j - 1]); 10 int l = 2, r = 7; 11 int k = log2(r - l + 1); // 长度 6 → k = 2 12 cout << max(st[l][k], st[r - (1 << k) + 1][k]); 13 return 0; 14}
单选题:程序输出是?([2,7] = {4,6,8,10,12,14} 的最大值)
考点:查询输出(L2)。
解析:[2,7] = max(st[2][2], st[4][2]) = max(10,14) = 14。正确答案 A。
实现要点:两段重叠覆盖。手算:max(4,6,8,10,12,14)。
排除法:B 是全局最大 16;C/D 无依据。
关联 · 查询两段覆盖(F2):概念题代码化。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int lg[9] = {0}; 05 for (int i = 2; i <= 8; i++) lg[i] = lg[i / 2] + 1; 06 for (int i = 1; i <= 8; i++) cout << lg[i] << " "; 07 return 0; 08}
单选题:程序输出是?(1~8 的 floor(log2))
考点:log 预处理(L3)。
解析:1~8 的 floor(log2) = 0 1 1 2 2 2 2 3。正确答案 A。
实现要点:lg[i] = lg[i/2] + 1 递推。手算:逐值验证。
排除法:B 是 +1 版本;C/D 无依据。
关联 · log 预处理(F3):概念题代码化。
01#include <bits/stdc++.h> 02using namespace std; 03int st[9][4]; 04int main() { 05 int a[9] = {0, 2, 4, 6, 8, 10, 12, 14, 16}; 06 for (int i = 1; i <= 8; i++) st[i][0] = a[i]; 07 for (int j = 1; (1 << j) <= 8; j++) 08 for (int i = 1; i + (1 << j) - 1 <= 8; i++) 09 st[i][j] = ______; // 两半取最大 10 cout << st[1][3]; 11 return 0; 12}
单选题:横线处应填入?(使输出为 16)
考点:建表填空(L4)。
解析:max(st[i][j-1], st[i + (1 << (j-1))][j-1])。正确答案 A。
实现要点:两半合并——第二半起点 i + 2^(j-1)。手算:st[1][3] = 16。
排除法:B 是求和;C/D 无依据。
关联 · 建表递推(F1):填空版。
01#include <bits/stdc++.h> 02using namespace std; 03int st[9][4]; 04int main() { 05 int a[9] = {0, 2, 4, 6, 8, 10, 12, 14, 16}; 06 for (int i = 1; i <= 8; i++) st[i][0] = a[i]; 07 for (int j = 1; (1 << j) <= 8; j++) 08 for (int i = 1; i + (1 << j) - 1 <= 8; i++) 09 st[i][j] = max(st[i][j - 1], st[i + (1 << (j - 1))][j - 1]); 10 int l = 1, r = 5; 11 int k = log2(r - l + 1); // 长度 5 → k = 2 12 cout << max(st[l][k], ______); // 第二段起点 r - 2^k + 1 13 return 0; 14}
单选题:横线处应填入?(使输出为 10——[1,5] 最大)
考点:查询填空(L5)。
解析:st[r - (1 << k) + 1][k]——第二段起点。正确答案 A。
实现要点:两段覆盖公式。手算:[1,5] 查 = max(st[1][2], st[2][2]) = 10。
排除法:B 漏 +1;C/D 无依据。
关联 · 查询公式(F5):填空版。
01#include <bits/stdc++.h> 02using namespace std; 03int st[9][4]; 04int main() { 05 int a[9] = {0, 3, 1, 4, 1, 5, 9, 2, 6}; 06 for (int i = 1; i <= 8; i++) st[i][0] = a[i]; 07 for (int j = 1; (1 << j) <= 8; j++) 08 for (int i = 1; i + (1 << j) - 1 <= 8; i++) 09 st[i][j] = max(st[i][j - 1], st[i + (1 << (j - 1))][j - 1]); 10 int l = 3, r = 6; 11 int k = log2(r - l + 1); // 长度 4 → k = 2 12 cout << max(st[l][k], st[r - (1 << k) + 1][k]); 13 return 0; 14}
单选题:程序输出是?([3,6] = {4,1,5,9} 的最大值)
考点:ST 综合(L6)。
解析:[3,6] = max(4,1,5,9) = 9。正确答案 A。
实现要点:完整建表 + 查询。手算:两段覆盖。
排除法:B/C/D 无依据。
关联 · ST 表实现(F6):完整代码。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 // 静态 RMQ → ST 表;单点改区间查 → 树状数组;区间改区间查最值 → 线段树 05 cout << "ST / BIT / SEGTREE"; 06 return 0; 07}
判断题:静态 RMQ 选 ST 表、单点改区间查选树状数组、区间改区间查最值选线段树——该选择全部合理。
考点:三结构选择(M1)。
解析:静态 RMQ → ST 表、单点改区间查 → 树状数组、区间改区间查最值 → 线段树——全合理。✅ 正确
实现要点:选型两问——改不改、可不可差分。手算:逐场景套。
排除法:无(判断题)。混淆点:最值类只能线段树(或 ST 静态)。
关联 · 选择矩阵(G2):概念题代码化。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 // 树状数组核心只有两个函数(add 与 sum)共约 10 行; 05 // 线段树(含 lazy)核心约 40 行 06 cout << "BIT shorter"; 07 return 0; 08}
判断题:实现"单点修改 + 区间求和",树状数组代码量远小于线段树且常数更小——能用树状数组就优先用它。
考点:线段树与树状数组代码量(M2)。
解析:树状数组约 10 行、线段树(lazy)约 40 行——能用树状数组优先用。✅ 正确
实现要点:代码量与常数的工程权衡。手算:两模板行数对比。
排除法:无(判断题)。混淆点:前提是操作可差分。
关联 · 与线段树的对比(A4):工程视角。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 // ST 表建好后不支持单点修改——改一个元素可能影响 O(n log n) 个状态 05 cout << "static only"; 06 return 0; 07}
判断题:ST 表是静态结构——元素修改后需 重建,因此只适合"建一次查多次"的场景。
考点:ST 表静态限制(M3)。
解析:改一个元素影响 个状态——只适合建一次查多次。✅ 正确
实现要点:静态性的代价分析。手算:状态依赖链。
排除法:无(判断题)。混淆点:动态 RMQ 必须线段树。
关联 · 与线段树对比(E6):静态约束。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 // 问题:区间最大公约数(gcd 幂等)+ 不修改 → ST 表 05 cout << "ST"; 06 return 0; 07}
判断题:区间 gcd 是幂等运算(gcd(x,x)=x),静态查询可用 ST 表(把 max 换成 gcd)——ST 表不止能做最值。
考点:选择矩阵(M4)。
解析:区间 gcd 幂等且静态 → ST 表(换合并函数即可)。✅ 正确
实现要点:ST 表通用性——一切幂等运算。手算:gcd(x,x) = x。
排除法:无(判断题)。混淆点:ST 表不止最值。
关联 · ST 表应用总表(G4):概念题代码化。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int n = 100000; 05 // 线段树/树状数组:O(n) 建 + O(log n) 每次 06 // ST 表:O(n log n) 建 + O(1) 每次 07 cout << n * (int)log2(n); 08 return 0; 09}
判断题:ST 表建表 (此处 )比线段树建树 贵,但查询 更快——用建表时间换查询时间。
考点:复杂度对比(M5)。
解析:ST 表建表 ()换查询 。✅ 正确
实现要点:建与查的时间权衡。手算:。
排除法:无(判断题)。混淆点:查询多时 ST 表划算。
关联 · 建表复杂度(E4):数字对比。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 // 选择流程:① 要修改吗?→ 是:线段树/树状数组;否:ST 表 05 // ② 操作可差分吗?→ 是:树状数组;否:线段树 06 cout << "flow ok"; 07 return 0; 08}
判断题:按"改不改 → 可不可差分"两步选型,能覆盖绝大多数区间问题。
考点:综合(M6)。
解析:选型流程 = ① 改不改 ② 可不可差分——两步定乾坤。✅ 正确
实现要点:选型决策树。手算:逐问过滤。
排除法:无(判断题)。混淆点:最值类在第②步落到线段树/ST 表。
关联 · 选择矩阵(G2):流程版。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int a[5] = {5, 3, 1, 4, 2}; 05 long long cnt = 0; 06 for (int i = 0; i < 5; i++) 07 for (int j = 0; j < i; j++) 08 if (a[j] > a[i]) cnt++; 09 cout << cnt; 10 return 0; 11}
单选题:程序输出是?({5,3,1,4,2} 的逆序对)
考点:逆序对(N1)。
解析:{5,3,1,4,2} 逆序对 7。正确答案 A。
实现要点:树状数组版 = 离散化 + 插入 + 前缀差。手算:逐对枚举验证。
排除法:B/C/D 无依据。
关联 · 逆序对输出(K4):同法双题。
01#include <bits/stdc++.h> 02using namespace std; 03int st[9][4]; 04int main() { 05 int a[9] = {0, 7, 2, 9, 4, 6, 1, 8, 3}; 06 for (int i = 1; i <= 8; i++) st[i][0] = a[i]; 07 for (int j = 1; (1 << j) <= 8; j++) 08 for (int i = 1; i + (1 << j) - 1 <= 8; i++) 09 st[i][j] = max(st[i][j - 1], st[i + (1 << (j - 1))][j - 1]); 10 int l = 4, r = 7; 11 int k = log2(r - l + 1); 12 cout << max(st[l][k], st[r - (1 << k) + 1][k]); 13 return 0; 14}
单选题:程序输出是?([4,7] = {4,6,1,8} 的最大值)
考点:ST 表 RMQ(N2)。
解析:[4,7] = max(4,6,1,8) = 8。正确答案 A。
实现要点:完整建表查询。手算:两段覆盖。
排除法:B 是全局最大 9;C/D 无依据。
关联 · ST 表解决的问题(E1):用途代码化。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 // 树状数组求第 k 小:二分 + 前缀和(此处直接演示二分查排名) 05 int cnt[9] = {0, 1, 0, 1, 1, 0, 1, 0, 0}; // 值 1、3、4、6 各 1 个 06 // 求第 3 小:前缀和第一个 >= 3 的位置 07 int k = 3, s = 0, ans = 0; 08 for (int i = 1; i <= 8; i++) { 09 s += cnt[i]; 10 if (s >= k) { ans = i; break; } 11 } 12 cout << ans; 13 return 0; 14}
单选题:程序输出是?(第 3 小的值)
考点:第 k 小思想(N3)。
解析:前缀和第一个 ≥ 3 的位置是 4。正确答案 A。
实现要点:树状数组 + 二分(或倍增)求第 k 小。手算:累计 cnt 到 3。
排除法:B 是第 2 小;C/D 无依据。
关联 · 树状数组应用总表(G3):第 k 小。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 // 差分:对 [2,5] +4 后,求整个数组(初始全 0)的元素 05 int a[7] = {0}; 06 int d[8] = {0}; 07 d[2] += 4; d[6] -= 4; // [2,5] +4 08 for (int i = 1; i <= 6; i++) a[i] = a[i - 1] + d[i]; 09 cout << a[3] << " " << a[6]; 10 return 0; 11}
单选题:程序输出是?(a[3] = 4、a[6] = 0)
考点:差分应用(N4)。
解析:[2,5]+4 → a[3] = 4、a[6] = 0。正确答案 A。
实现要点:差分两处修改 + 前缀还原。手算:diff[2]+=4、diff[6]-=4。
排除法:B 顺序反;C/D 无依据。
关联 · 差分实现区间加单点查(D2):用途代码化。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int x = 6, s = 0; 05 while (x > 0) { s += x % 2; ______; } // 数二进制 1 的个数 06 cout << s; 07 return 0; 08}
单选题:横线处应填入?(使输出为 2——6 = 110 有两个 1)
考点:应用填空(N5)。
解析:x >>= 1——逐位右移数 1。正确答案 A。
实现要点:二进制位计数(与 lowbit 法等价)。手算:110 右移两次。
排除法:B 左移死循环;C/D 无依据。
关联 · lowbit 综合(I6):同目标两写法。
01#include <bits/stdc++.h> 02using namespace std; 03int st[9][4]; 04int main() { 05 int a[9] = {0, 1, 5, 2, 8, 3, 9, 4, 7}; 06 for (int i = 1; i <= 8; i++) st[i][0] = a[i]; 07 for (int j = 1; (1 << j) <= 8; j++) 08 for (int i = 1; i + (1 << j) - 1 <= 8; i++) 09 st[i][j] = max(st[i][j - 1], st[i + (1 << (j - 1))][j - 1]); 10 int l = 1, r = 8; 11 int k = log2(r - l + 1); // k = 3 12 cout << max(st[l][k], st[r - (1 << k) + 1][k]); 13 return 0; 14}
单选题:程序输出是?(全区间 [1,8] 的最大值)
考点:综合(N6)。
解析:[1,8] 全区间最大 = 9。正确答案 A。
实现要点:k=3 时两段都覆盖全区间。手算:max(9, 8)。
排除法:B/C/D 无依据。
关联 · ST 综合(L6):全区间特例。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int x = 10; // 1010 05 cout << ______; // lowbit(10) = 2 06 return 0; 07}
单选题:横线处应填入?(使输出为 2)
考点:lowbit 填空(O1)。
解析:x & (-x)——10 = 1010 → 2。正确答案 A。
实现要点:lowbit 公式。手算:1010 & 0110 = 0010。
排除法:B 是去 1;C/D 无依据。
关联 · lowbit 输出(I1):填空版。
01#include <bits/stdc++.h> 02using namespace std; 03int c[9] = {0}; 04void add(int i, int v) { 05 while (i <= 8) { 06 c[i] += v; 07 ______; // lowbit 上跳 08 } 09} 10int main() { 11 add(3, 2); 12 cout << c[4]; // 3 的路径含 4 13 return 0; 14}
单选题:横线处应填入?(使输出为 2)
考点:add 填空(O2)。
解析:i += (i & (-i))——上跳。正确答案 A。
实现要点:add 方向。手算:3→4 后 c[4] = 2。
排除法:B 下跳(sum 方向);C/D 无依据。
关联 · add 单点加(C1):填空版。
01#include <bits/stdc++.h> 02using namespace std; 03int c[9] = {0, 1, 4, 5, 16, 9, 20, 13, 64}; 04int sum(int x) { 05 int s = 0; 06 while (x > 0) { 07 s += c[x]; 08 ______; // lowbit 下跳 09 } 10 return s; 11} 12int main() { 13 cout << sum(4); 14 return 0; 15}
单选题:横线处应填入?(使输出为 16)
考点:sum 填空(O3)。
解析:x -= (x & (-x))——下跳。正确答案 A。
实现要点:sum 方向。手算:4 → 0,sum(4) = c[4] = 16。
排除法:B 上跳;C/D 无依据。
关联 · sum 前缀查询(C3):填空版。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int d[7] = {0}; // 差分数组(初始 a 全 0) 05 int l = 2, r = 5, v = 3; 06 d[l] += v; 07 ______; // 区间加 [l,r] 的差分 08 int a[6] = {0}, s = 0; 09 for (int i = 1; i <= 5; i++) a[i] = a[i - 1] + d[i]; 10 for (int i = 1; i <= 5; i++) s += a[i]; 11 cout << s; 12 return 0; 13}
单选题:横线处应填入?(使输出为 12——[2,5] 共 4 个 × 3)
考点:差分填空(O4)。
解析:d[r + 1] -= v。正确答案 A。
实现要点:区间加差分两处。手算:还原后 [2,5] 各 3。
排除法:B 漏 +1;C 位置错;D 符号反。
关联 · 差分方向(H4):填空版。
01#include <bits/stdc++.h> 02using namespace std; 03int st[9][4]; 04int main() { 05 int a[9] = {0, 2, 4, 6, 8, 10, 12, 14, 16}; 06 for (int i = 1; i <= 8; i++) st[i][0] = a[i]; 07 for (int j = 1; (1 << j) <= 8; j++) 08 for (int i = 1; i + (1 << j) - 1 <= 8; i++) 09 ______; // 两半合并 10 cout << st[1][2]; 11 return 0; 12}
单选题:横线处应填入?(使输出为 8——st[1][2] 是 [1,4] 的最大值)
考点:ST 建表填空(O5)。
解析:st[i][j] = max(st[i][j-1], st[i + (1 << (j-1))][j-1])。正确答案 A。
实现要点:两半合并。手算:st[1][2] = 8。
排除法:B 求和;C/D 无依据。
关联 · 建表递推(F1):填空版。
01#include <bits/stdc++.h> 02using namespace std; 03int st[9][4]; 04int main() { 05 int a[9] = {0, 2, 4, 6, 8, 10, 12, 14, 16}; 06 for (int i = 1; i <= 8; i++) st[i][0] = a[i]; 07 for (int j = 1; (1 << j) <= 8; j++) 08 for (int i = 1; i + (1 << j) - 1 <= 8; i++) 09 st[i][j] = max(st[i][j - 1], st[i + (1 << (j - 1))][j - 1]); 10 int l = 2, r = 5; 11 int k = ______; // 区间长度取 log 12 cout << max(st[l][k], st[r - (1 << k) + 1][k]); 13 return 0; 14}
单选题:横线处应填入?(使输出为 10——[2,5] 的最大值)
考点:ST 查询填空(O6)。
解析:log2(r - l + 1)——区间长度取 log。正确答案 A。
实现要点:k 的选取。手算:长度 4 → k=2。
排除法:B 少 1;C/D 无依据。
关联 · 区间长度选取(F4):填空版。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 // 前缀 [1,x] 的二进制分解段数 = x 的二进制 1 的个数 05 int x = 6; // 110 06 int cnt = 0; 07 while (x) { cnt++; x -= (x & (-x)); } 08 cout << cnt; 09 return 0; 10}
单选题:程序输出是?(sum(6) 累加的节点数)
考点:综合填空(O7)。
解析:sum(6) 累加 2 个节点(6、4)。正确答案 A。
实现要点:段数 = 二进制 1 的个数。手算:110 两个 1。
排除法:B/C/D 无依据。
关联 · 结构综合(B7):段数视角。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int i = 3, n = 8; 05 int steps = 0; 06 while (i <= n) { 07 i += (i & (i - 1)); // 错误:这是"去掉最低位 1",不是 lowbit 08 steps++; 09 if (steps > 20) break; // 防死循环 10 } 11 cout << steps; 12 return 0; 13}
判断题:add 循环里把 lowbit 写成 i & (i - 1)(去 1 而非 lowbit)会导致跳转错乱——i=3 时 3&2=2、i 变 5、5&4=4、i 变 9 越界——路径完全错误。
考点:lowbit 写成 0(P1)。
解析:i & (i-1) 是"去 1"不是 lowbit——i=3 时跳 3→5→9 越界路径错乱。✅ 正确
实现要点:lowbit 与去 1 是两个函数。手算:3&2=2、5&4=4。
排除法:无(判断题)。混淆点:形近位运算函数的区分。
关联 · lowbit 写错(H1):错误示范。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int i = 0; 05 // 错误:下标 0 起,i += lowbit(i) = 0 恒成立 → 死循环 06 int steps = 0; 07 while (i <= 8) { 08 i += (i & (-i)); // 0 + 0 = 0 09 steps++; 10 if (steps > 100) break; 11 } 12 cout << steps; 13 return 0; 14}
判断题:树状数组下标 0 起会死循环(lowbit(0) = 0)——必须下标 1 起。
考点:下标 0 起(P2)。
解析:lowbit(0) = 0 → i += 0 死循环。✅ 正确
实现要点:下标 1 起是硬约束。手算:0 恒 0。
排除法:无(判断题)。混淆点:死循环不报错、程序卡死。
关联 · 下标 0 起错误(H2):错误示范。
01#include <bits/stdc++.h> 02using namespace std; 03int st[9][4]; 04int main() { 05 int a[9] = {0, 2, 4, 6, 8, 10, 12, 14, 16}; 06 for (int i = 1; i <= 8; i++) st[i][0] = a[i]; 07 for (int j = 1; (1 << j) <= 8; j++) 08 for (int i = 1; i + (1 << j) - 1 <= 8; i++) 09 st[i][j] = max(st[i][j - 1], st[i + (1 << (j - 1))][j - 1]); 10 int l = 6, r = 8; 11 int k = log2(r - l + 1); // 长度 3 → k = 1 12 // 错误:第二段起点写成 r - (1 << k)(漏 +1)→ 覆盖 [5,6],漏了 8 13 cout << max(st[l][k], st[r - (1 << k)][k]); 14 return 0; 15}
单选题:程序输出是?(漏 +1 的第二段覆盖 [5,6] 而非 [7,8]——结果错为 14,正确是 16)
考点:ST 查询越界(P3)。
解析:漏 +1 → 第二段覆盖 [5,6] 漏掉 8 → 结果 14(正确 16)。正确答案 A。
实现要点:第二段起点 r - (1 << k) + 1。手算:8-2 = 6 vs 7。
排除法:B 是正确值;C/D 无依据。
关联 · ST 表查询段选取错(H3):错误示范。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 int d[7] = {0}; 05 int l = 2, r = 5, v = 3; 06 d[l] -= v; // 错误:方向反 07 d[r + 1] += v; // 错误:方向反 08 int a[6] = {0}, s = 0; 09 for (int i = 1; i <= 5; i++) a[i] = a[i - 1] + d[i]; 10 for (int i = 1; i <= 5; i++) s += a[i]; 11 cout << s; 12 return 0; 13}
单选题:程序输出是?(方向反 → 区间内是 -3 而非 +3,总和 -12;正确应为 12)
考点:差分方向反(P4)。
解析:符号反 → 区间内 -3、总和 -12(正确 12)。正确答案 A。
实现要点:l 加 r+1 减。手算:方向对照。
排除法:B 是正确值;C/D 无依据。
关联 · 差分方向错(H4):错误示范。
01#include <bits/stdc++.h> 02using namespace std; 03int main() { 04 // 错误:值域 10^9 直接用值作树状数组下标 05 int value = 1000000000; 06 int c[1000] = {0}; // 数组只开 1000 07 // c[value]++ 将严重越界 08 cout << value; 09 return 0; 10}
判断题:值域 时直接用值作树状数组下标必然越界——必须先离散化把值映射到排名。
考点:忘离散化(P5)。
解析:值域 直接用值作下标必越界——先离散化。✅ 正确
实现要点:树状数组下标 = 排名。手算:值 10^9 的下标需求。
排除法:无(判断题)。混淆点:越界是静默错误。
关联 · 树状数组与离散化(D5):错误示范。
判断题:以下结论全部正确——"lowbit 用 x&-x;add 上跳、sum 下跳;下标 1 起;ST 表查询两段为 [l, l+2^k-1] 与 [r-2^k+1, r];差分区间加是 l 加、r+1 减"。
考点:综合判断(P6)。
解析:五结论全对——lowbit x&-x、add 上跳 sum 下跳、下标 1 起、ST 两段 [l,l+2^k-1] 与 [r-2^k+1,r]、差分 l 加 r+1 减。✅ 正确
实现要点:本章两大结构模板要点收官自查。手算:逐条对照本章代码。
排除法:无(判断题)。混淆点:本卷与线段树卷(27 章)共同构成区间问题三板斧。
关联 · 本章全部核心结论:收官综合判断题。