一维树状数组总结
树状数组比线段树短小多了 我喜欢这个...
1.单点修改 区间查询
这是最简单的树状数组了 求[l,r]前缀和之差即为区间的和
代码
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 500000+10;
int m,n,c[N],tree[N];
long long ans;
int lowbit(int x){
return x&(-x);
}
void add(int x,int val){
while(x <= n){
tree[x] += val;
x += lowbit(x);
}
}
long long get_sum(int x){
long long ans = 0;
while(x > 0){
ans += tree[x];
x -= lowbit(x);
}
return ans;
}
int main(){
scanf("%d%d",& n,& m);
for(int i = 1;i <= n;i ++){
scanf("%d",& c[i]);
add(i,c[i]);
}
for(int i = 1;i <= m;i ++){
int q,a,b;
scanf("%d%d%d",& q,& a,& b);
if(q == 1) add(a,b);
else{
ans = get_sum(b)-get_sum(a-1);
printf("%I64d\n",ans);
}
}
return 0;
}
2.区间修改 单点查询
此处的树状数组前缀和不是每个数的和 而是对应位置上那个数的值
怎么实现呢 就用一个变量cmp保存之前的前缀和(也就是上一个位置数的值)
要想让前缀和为本位置上的数 就在该位置上加上 a[i]-cmp 就好了
怎么修改呢
这里运用差分的思想 在[l,r]的l上加上你想修改的值 在r+1位置上再减去就好了
这样子差分数组前缀和就是你现在对应的值
代码
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
typedef long long ll;
using namespace std;
const int N = 500000+10;
int n,m,a[N],tree[N],cmp;
int lowbit(int x){
return x&(-x);
}
void add(int x,int val){
while(x <= n){
tree[x] += val;
x += lowbit(x);
}
}
int get(int x){
int sum = 0;
while(x){
sum += tree[x];
x -= lowbit(x);
}
return sum;
}
int main(){
scanf("%d%d",& n,& m);
for(int i = 1;i <= n;i ++){
scanf("%d",& a[i]);
add(i,a[i]-cmp);
cmp = a[i];
}
for(int i = 1;i <= m;i ++){
int q;
scanf("%d",& q);
if(q == 1){
int x,y,k;
scanf("%d%d%d",& x,& y,& k);
add(x,k);
add(y+1,-k);
}
else{
int x;
scanf("%d",& x);
printf("%d\n",get(x));
}
}
return 0;
}
3.区间修改 区间查询
和上面的思想类似
位置p前缀和可以表示为:
d是差分数组 a是原本的数组
整理得:
那么我们可以维护两个数组
一个是 差分数组d[i] 另一个是 d[i]*i
查询如上式
修改也是一样 d[i]如第二点 d[i]*i 也是对应加上 修改值*i即可
代码
这个代码原出处 点击打开链接
void add(ll p, ll x){
for(int i = p; i <= n; i += i & -i)
sum1[i] += x, sum2[i] += x * p;
}
void add(ll l, ll r, ll x){
add(l, x), add(r + 1, -x);
}
ll ask(ll p){
ll res = 0;
for(int i = p; i; i -= i & -i)
res +=(p + 1) * sum1[i] - sum2[i];
return res;
}
ll range_ask(ll l, ll r){
return ask(r) - ask(l - 1);
}
完。