树状数组学习
树状数组主要用于处理:单点修改区间查询 的问题
如上图
可以看得出来,如果
x
≡
0
(
m
o
d
2
n
)
x\equiv 0 \left(\mathop{mod} 2^n\right)
x≡0(mod2n),
n
n
n取最大整数值,那么
c
x
c_x
cx管理的区间长度为
2
n
2^n
2n
n
n
n也是
x
x
x最低位的
1
1
1右边的
0
0
0的个数
取最低位的 1 1 1,可以用
//最低位1
int lowbit(int x) {
return x & -x;
}
所以 c x c_x cx管理的区间为 [ x − l o w b i t ( x ) + 1 , x ] \left[x - lowbit(x) + 1, x\right] [x−lowbit(x)+1,x]
单点修改
//a[x] += k
void add(int x, int k) {
while (x <= n) {
c[x] += k;
x += lowbit(x);
}
}
前缀和
//a[1]+a[2] + ... +a[x]
int query(int x) {
int ans = 0;
while (x >= 1) {
ans += c[x];
x -= lowbit(x);
}
return ans;
}
建树
//建树
void init() {
int temp, j;
for (int i = 1; i <= n; ++i) {
scanf("%d", &temp);
c[i] += temp;
j = i + lowbit(i);
if (j <= n)c[j] += c[i];
}
}
洛谷P3374
单点修改+单点查询
#include<cstdio>
const int N = 5e5 + 5;
int c[N];//树状数组
int n;//长度
//最低位1
int lowbit(int x) {
return x & -x;
}
//建树
void init() {
int temp, j;
for (int i = 1; i <= n; ++i) {
scanf("%d", &temp);
c[i] += temp;
j = i + lowbit(i);
if (j <= n)c[j] += c[i];
}
}
//a[x] += k
void add(int x, int k) {
while (x <= n) {
c[x] += k;
x += lowbit(x);
}
}
//a[1]+a[2] + ... +a[x]
int query(int x) {
int ans = 0;
while (x >= 1) {
ans += c[x];
x -= lowbit(x);
}
return ans;
}
int main() {
int m, x, y, z;
scanf("%d%d", &n, &m);
init();
while (m--) {
scanf("%d%d%d", &x, &y, &z);
if (x == 1) {
add(y, z);
}
else {
printf("%d\n", query(z) - query(y - 1));
}
}
return 0;
}
洛谷P3368
区间修改+区间查询
利用差分
b
[
i
]
=
a
[
i
]
−
a
[
i
−
1
]
b[i] = a[i] - a[i-1]
b[i]=a[i]−a[i−1]
给
[
l
,
r
]
[l,r]
[l,r]加上
x
x
x,则
b
[
l
]
=
b
[
l
]
+
x
,
b
[
r
+
1
]
=
b
[
r
+
1
]
−
x
b[l] = b[l] +x,b[r + 1] = b[r+1] -x
b[l]=b[l]+x,b[r+1]=b[r+1]−x,其他位置没有变化
#include<cstdio>
const int N = 500005;
int d[N];//差分树状数组
int n;
int lowbit(int x) {
return x & -x;
}
void init() {
int temp, j, pre = 0;
for (int i = 1; i <= n; ++i) {
scanf("%d", &temp);
d[i] += temp - pre;
pre = temp;
j = i + lowbit(i);
if (j <= n)d[j] += d[i];
}
}
void add(int x, int k) {
while (x <= n) {
d[x] += k;
x += lowbit(x);
}
}
void range_add(int l, int r, int k) {
add(l, k);
add(r + 1, -k);
}
int query(int x) {
int ans = 0;
while (x >= 1) {
ans += d[x];
x -= lowbit(x);
}
return ans;
}
int main() {
int m, t, x, y, z;
scanf("%d%d", &n, &m);
init();
while (m--) {
scanf("%d%d", &t, &x);
if (t == 1) {
scanf("%d%d", &y, &z);
range_add(x, y, z);
}
else {
printf("%d\n", query(x));
}
}
return 0;
}
LOJ131
区间修改+区间求和
∑
i
=
1
r
a
i
=
∑
i
=
1
r
∑
j
=
1
i
b
j
=
∑
i
=
1
r
b
i
×
(
r
−
i
+
1
)
=
∑
i
=
1
r
b
i
×
(
r
+
1
)
−
∑
i
=
1
r
b
i
×
i
\begin{aligned} &\sum_{i=1}^{r} a_i\\ =&\sum_{i=1}^{r}\sum_{j=1}^{i}b_j\\ =&\sum_{i=1}^{r} b_i\times\left(r-i+1\right)\\ =&\sum_{i=1}^{r}b_i\times\left(r+1\right)-\sum_{i=1}^{r}b_i\times i \end{aligned}
===i=1∑raii=1∑rj=1∑ibji=1∑rbi×(r−i+1)i=1∑rbi×(r+1)−i=1∑rbi×i
因此可以维护
b
i
b_i
bi和
b
i
×
i
b_i\times i
bi×i
#include<cstdio>
typedef long long LL;
const int N = 6e6 + 5;
LL d1[N]; //差分树状数组
LL d2[N]; //差分*i树状数组
int n;
int lowbit(int x) {
return x & -x;
}
void init() {
LL temp, pre = 0;
int j;
for (int i = 1; i <= n; ++i) {
scanf("%lld", &temp);
d1[i] += temp - pre;
d2[i] += i * (temp - pre);
pre = temp;
j = i + lowbit(i);
if (j <= n) {
d1[j] += d1[i];
d2[j] += d2[i];
}
}
}
void add(int x, int k) {
LL k2 = 1LL * x * k;
while (x <= n) {
d1[x] += k;
d2[x] += k2;
x += lowbit(x);
}
}
void range_add(int l, int r, int k) {
add(l, k);
add(r + 1, -k);
}
LL get_sum(LL d[], int x) {
LL ans = 0;
while (x >= 1) {
ans += d[x];
x -= lowbit(x);
}
return ans;
}
LL query(int l, int r) {
return (r + 1) * get_sum(d1, r) - l * get_sum(d1, l - 1) - get_sum(d2, r) + get_sum(d2, l - 1);
}
int main() {
int m, t, x, y, z;
scanf("%d%d", &n, &m);
init();
while (m--) {
scanf("%d%d%d", &t, &x, &y);
if (t == 1) {
scanf("%d", &z);
range_add(x, y, z);
}
else {
printf("%lld\n", query(x, y));
}
}
return 0;
}
相关文章
- Knockout.Js官网学习(数组observable)
- 小姐姐带你一起学:如何用Python实现7种机器学习算法(附代码)
- 从了解机器学习开始
- Swift学习(1)
- Opencv学习笔记 - 频域手段添加盲水印
- 机器学习笔记 - TensorFlow2.0全卷积网络FCN图像分类
- Python编程语言学习:仅需一行代码将字符串化的数字数组、int数组、float数组实现之间互换(将一个字符串数组转换成整型数组)
- Python编程语言学习:仅需一行代码将字符串化的数字数组、int数组、float数组实现之间互换(将一个字符串数组转换成整型数组)
- 爬虫学习(9):python 自动发送QQ邮箱
- Scala学习教程笔记一之基础语法,条件控制,循环控制,函数,数组,集合
- Linux 中断学习之小试牛刀篇---Linux中断内核编程
- nginx学习七 高级数据结构之动态数组ngx_array_t
- Py中的多维数组ndarray学习【转载】
- Java学习笔记(五)——数组
- 【NLP】讯飞英文学术论文分类挑战赛Top10开源多方案–4 机器学习LGB 方案
- 【必学】从入门到资深,云原生技术学习地图
- 【Nginx 源码学习】动态数组
- 简单粗暴地入门机器学习