树状数组学习记录
树状数组真是一个好东西啊QAQ,代码短且好写。
首先它的原理是半二叉树,差不多可以这么叫吧,,,
比较重要的 l o w b i t lowbit lowbit操作:
int lowbit(int x){
return x&(-x);
}
x&(-x),当x为0时结果为0;
x为奇数时,结果为1;
x为偶数时,结果为x中2的最大次方的因子。
建树时
c
[
i
]
=
a
[
i
−
2
k
+
1
]
+
a
[
i
−
2
k
+
2
]
+
.
.
.
+
a
[
i
]
c[i]=a[i-2^k+1]+a[i-2^k+2]+...+a[i]
c[i]=a[i−2k+1]+a[i−2k+2]+...+a[i]
求和时
s
u
m
[
i
]
=
c
[
i
]
+
c
[
i
−
2
k
1
]
+
c
[
(
i
−
2
k
1
)
−
2
k
2
]
.
.
.
;
sum[i]=c[i]+c[i-2^{k1}]+c[(i-2^{k1})-2^{k2}]...;
sum[i]=c[i]+c[i−2k1]+c[(i−2k1)−2k2]...;
那么就可以建树了
int n;
int a[N],c[N]; //对应原数组和树状数组
int lowbit(int x){
return x&(-x);
}
void updata(int i,int k){ //在i位置加上k
while(i <= n){
c[i] += k;
i += lowbit(i);
}
}
int getsum(int i){ //求A[1 - i]的和
int res = 0;
while(i > 0){
res += c[i];
i -= lowbit(i);
}
return res;
}
int main(int argc, char const *argv[]) {
for(int i=1;i<=n;i++){
cin>>a[i];
update(i,a[i]);
}
return 0;
}
这样子就可以进行简单的单点更新,区间求和。
区间更新,单点求和
要进行区间更新只需要用差分数组来建树即可,总体模板不变,只需要更改建树的操作即可
经过一系列的推导:
在更新
(
l
,
r
)
(l,r)
(l,r)区间时只需要更新
c
[
l
]
+
k
,
c
[
r
+
1
]
−
k
c[l]+k,c[r+1]-k
c[l]+k,c[r+1]−k即可。
注意此时查询的
g
e
t
s
u
m
getsum
getsum函数返回的值为
a
[
i
]
a[i]
a[i]位置上的值而非前缀和的值。
for(int i = 1; i <= n; i++){
cin>>a[i];
updata(i,a[i] - a[i-1]); //输入初值的时候,也相当于更新了值
}
区间更新,区间查询
这个就比较麻烦,同样是使用差分数组来维护,但是需要更改
u
p
d
a
t
e
update
update函数及
g
e
t
s
u
m
getsum
getsum函数。
经过一系列推导:
只需要维护俩个数组
s
u
m
1
sum1
sum1及
s
u
m
2
sum2
sum2即可。
int n,m;
int a[50005] = {0};
int sum1[50005]; //(D[1] + D[2] + ... + D[n])
int sum2[50005]; //(1*D[1] + 2*D[2] + ... + n*D[n])
int lowbit(int x){
return x&(-x);
}
void updata(int i,int k){
int x = i; //因为x不变,所以得先保存i值
while(i <= n){
sum1[i] += k;
sum2[i] += k * (x-1);
i += lowbit(i);
}
}
int getsum(int i){ //求前缀和
int res = 0, x = i;
while(i > 0){
res += x * sum1[i] - sum2[i];
i -= lowbit(i);
}
return res;
}
int main(){
cin>>n;
for(int i = 1; i <= n; i++){
cin>>a[i];
updata(i,a[i] - a[i-1]); //输入初值的时候,也相当于更新了值
}
//[x,y]区间内加上k
updata(x,k); //A[x] - A[x-1]增加k
updata(y+1,-k); //A[y+1] - A[y]减少k
//求[x,y]区间和
int sum = getsum(y) - getsum(x-1);
return 0;
}
好了这样子一个logn的数据结果就学完了,是不是觉得特别轻松呢hhhhhh
本菜鸡用了好几个小时呢QAQ
参考博客:https://www.cnblogs.com/xenny/p/9739600.html