AcWing算法提高课 树状数组
解决的问题:
1、快速求前缀和(logn)(区间求和)
2、修改某一个数(logn)(单点修改)
对比:数组:求前缀和On,修改O1;前缀和数组:求前缀和O1,修改On
C[x]表示,以x结尾,长度为lowbit(x)的区间中的计数
查询:
修改:
模板:

int a[200010]; LL tr[200010]; int n; int lowbit(int x) { return x & (-x); } int add(int x, int c) { for (int i = x; i <= n; i += lowbit(i)) { tr[i] += c; } return 0; } LL sum(int x) { LL res = 0; for (int i = x; i > 0; i -= lowbit(i)) res += tr[i]; return res; }
对称问题:
区间修改,单点查询
可以转化为对差分数组的单点(两点)修改,区间查询
例题:
AcWing 242. 一个简单的整数问题

#include<bits/stdc++.h> #include<unordered_set> using namespace std; typedef long long LL; LL a[100010]; LL diff[100010]; LL tr[100010]; int n, m; LL lowbit(int x) { return x & (-x); } void add(LL x, LL c) { for (int i = x; i <= n; i += lowbit(i)) { tr[i] += c; } } LL sum(LL x) { LL res = 0; for (int i = x; i > 0; i -= lowbit(i)) { res += tr[i]; } return res; } void YD() { cin >> n >> m; for (int i = 1; i <= n; i++) cin >> a[i], diff[i] = a[i] - a[i - 1]; for (int i = 1; i <= n; i++) { add(i, diff[i]); } for (int i = 1; i <= m; i++) { char op; cin >> op; if (op == 'Q') { int x; cin >> x; cout << sum(x) << endl; } else { LL l, r, d; cin >> l >> r >> d; add(r+1, -d); add(l, d); } } } int main() { YD(); return 0; }
拓展问题:
区间修改,区间查询
修改依旧使用差分数组。
区间查询,前缀和的前缀和,转化为不同形式的前缀和的差
例题:AcWing 243. 一个简单的整数问题2

#include<bits/stdc++.h> using namespace std; typedef long long LL; LL a[100010]; int n, m; LL tr1[100010]; LL tr2[100010]; LL lowbit(LL x) { return x & (-x); } void add(LL x, LL c) { for (int i = x; i <= n; i += lowbit(i)) { tr1[i] += c; } } LL sum(LL x) { LL res = 0; for (int i = x; i >0; i -= lowbit(i)) { res += tr1[i]; } return res; } void add2(LL x, LL c) { for (int i = x; i <= n; i += lowbit(i)) { tr2[i] += c; } } LL sum2(LL x) { LL res = 0; for (int i = x; i > 0; i -= lowbit(i)) { res += tr2[i]; } return res; } void YD() { cin >> n >> m; for (int i = 1; i <= n; i++) cin >> a[i]; for (int i = 1; i <= n; i++) { add(i, a[i] - a[i - 1]); add2(i, (a[i] - a[i - 1])*i); } while (m--) { char op; cin >> op; if (op == 'C') { LL l, r, d; cin >> l >> r >> d; add(l, d); add(r + 1, -d); add2(l, l*d); add2(r + 1, -d*(r+1)); } else { LL l, r; cin >> l >> r ; cout << sum(r)*(r + 1) - sum2(r) - (sum(l - 1)*(l)-sum2(l - 1)) << endl; } } } int main() { YD(); return 0; }
树状数组结合二分例题
244. 谜一样的牛

#include<bits/stdc++.h> using namespace std; typedef long long LL; int a[100010]; int n, m; int h[100010]; int tr[100010]; int lowbit(int i) { return i & (-i); } void add(int x, int c) { for (int i = x; i <= n; i += lowbit(i)) tr[i] += c; } int sum(int x) { int res = 0; for (int i = x; i > 0; i -= lowbit(i)) res += tr[i]; return res; } void YD() { cin >> n; a[1] = 0; for (int i = 2; i <= n; i++) cin >> a[i]; for (int i = 1; i <= n; i++) { tr[i] = lowbit(i); } for (int i = n; i >= 0; i--) { int index = a[i] + 1; int l = 1, r = n; while (l < r) { int mid = (l + r) / 2; if (sum(mid) >= index) r = mid; else l = mid + 1; } h[i] = l; add(l, -1); } for (int i = 1; i <= n; i++) cout << h[i] << endl; } int main() { YD(); return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· winform 绘制太阳,地球,月球 运作规律
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人