笔记——树状数组
蓝月の笔记——树状数组篇
在可恶的OI里,我们尝尝会遇到一些区间问题,例如区间修改单点查询,单点修改区间查询,区间修改单点查询,单点修改单点查询。
其中,单点修改区间查询,就是树状数组最经典的用法啦!
给定一个长度为
- 输入
1 x k
将 加上 ; - 输入
2 l r
,求 。
这就是我们说的单点修改区间查询。
根据前缀和的思想,我们可以用一些手法求出每一个
首先我们设树状数组的数组(?)为数组
定义
我们引入一个函数,叫
举个例子:
我们注意到
我们充分发扬人类智慧,将
而根据补码的性质
int L(int x) {
return x & -x;
}
如果你喜欢写成宏定义的话:
#define L(x) ((x) & (-x))
还是已
我们前面手算的也是
先放图。
【图片转载自liruixiong0101的blog】
观察这棵树,可以发现
void U(int x, int y) {
for (int i = x; i <= n; i += L(i)) {
c[i] += y;
}
}
根据设计,
根据定义,
我们现在
现在我们在
一直持续这个操作,直到
根据思路写出代码:
int Q(int x) {
int ans = 0;
for (int i = x; i; i -= L(i)) {
ans += c[i];
}
return ans;
}
然后求 Q(r) - Q(l - 1)
。
然后我们就可以写完这道水黄力!(喜
已用结构体封装好的代码:
// P3374
#include<bits/stdc++.h>
using namespace std;
const int kMaxN = 5e5 + 5;
int L(int x) {
return x & -x;
}
struct BIT {
int n, a[kMaxN], c[kMaxN];
void U(int x, int y) {
for (int i = x; i <= n; i += L(i)) {
c[i] += y;
}
}
int Q(int x) {
int ans = 0;
for (int i = x; i; i -= L(i)) {
ans += c[i];
}
return ans;
}
};
int m, op, l, r;
BIT t;
int main()
{
cin >> t.n >> m;
for (int i = 1; i <= t.n; i++) {
cin >> t.a[i];
t.U(i, t.a[i]);
}
for (; m; m--) {
cin >> op >> l >> r;
if(op == 1) {
t.U(l, r);
} else {
cout << t.Q(r) - t.Q(l - 1) << '\n';
}
}
return 0;
}
友情给出树状数组结构体:(
struct BIT {
int n, a[kMaxN], c[kMaxN];
void U(int x, int y) {
for (int i = x; i <= n; i += L(i)) {
c[i] += y;
}
}
int Q(int x) {
int ans = 0;
for (int i = x; i; i -= L(i)) {
ans += c[i];
}
return ans;
}
};
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· DeepSeek在M芯片Mac上本地化部署