树状数组利用二进制,删掉线段树中不需要的点,再把剩下的节点对应到数组中。
树状数组的查询与修改时间复杂度都是O(logn),且它的常数系数比线段树小,代码量也比线段树少得多。
树状数组能解决的问题,线段树都能解决,但是线段树能解决的问题,树状数组却不一定能解决,其功能比线段树要差一些。
蓝色代表区间覆盖长度,橙色代表初始数组数值,tree[4] = a[1] + a[2] + a[3] + a[4],tree[1] = a[1];
int lowbit(int x)
{
return x & (-x);
}
int query(int x)
{
int res = 0;
while(x){
res += tree[x];
x -= lowbit(x);
}
return res;
}
洛谷 P3374
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int maxn = 1e6 + 10;
int n,a[maxn],d[maxn];
int lowbit(int x)
{
return x & (-x);
}
void add(int x,int val)
{
while(x <= n){
d[x] += val;
x += lowbit(x);
}
}
int query(int x)
{
int res = 0;
while(x){
res += d[x];
x -= lowbit(x);
}
return res;
}
int main()
{
int q;
scanf("%d%d",&n,&q);
for(int i = 1; i <= n; i++)
{
scanf("%d",&a[i]);
add(i,a[i]);
}
for(int i = 1; i <= q; i++)
{
int k,x,y;
scanf("%d%d%d",&k,&x,&y);
if(k == 1){
add(x,y);
}
else if(k == 2){
int sum1 = query(x - 1);
int sum2 = query(y);
printf("%d\n",sum2 - sum1);
}
}
return 0;
}
洛谷 P3368
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int maxn = 1e6 + 10;
ll n,m,a[maxn],d[maxn];
ll lowbit(ll x)
{
return x & (-x);
}
void add(ll x,ll val)
{
while(x <= n){
d[x] += val;
x += lowbit(x);
}
}
ll query(ll x)
{
ll res = 0;
while(x){
res += d[x];
x -= lowbit(x);
}
return res;
}
int main()
{
scanf("%lld%lld",&n,&m);
for(int i = 1; i <= n; i++)
{
scanf("%lld",&a[i]);
add(i,a[i] - a[i-1]);
}
for(int i = 1; i <= m; i++)
{
int flag;
scanf("%d",&flag);
if(flag == 1)
{
ll x,y,k;
scanf("%lld %lld %lld",&x,&y,&k);
add(x,k);
add(y+1,-k);
}
else{
ll x;
scanf("%lld",&x);
printf("%lld\n",query(x));
}
}
return 0;
}
维护两个树状数组
poj - 3468 A Simple Problem with Integers
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int maxn = 1e6 + 10;
ll n,q,a[maxn],sum1[maxn],sum2[maxn];
ll lowbit(ll x)
{
return x & (-x);
}
void add(ll x,ll val)
{
ll j = x;
while(x <= n){
sum1[x] += val;
sum2[x] += val * (j - 1);
x += lowbit(x);
}
}
ll query(ll x)
{
ll res = 0, j = x;
while(x){
res += j * sum1[x] - sum2[x];
x -= lowbit(x);
}
return res;
}
int main()
{
cin>>n>>q;
for(int i = 1; i <= n; i++)
{
cin>>a[i];
add(i,a[i] - a[i-1]);
}
for(int i = 1; i <= q; i++)
{
char flag;
scanf(" %c",&flag);
if(flag == 'C')
{
ll l,r,k;
cin>>l>>r>>k;
add(l,k);
add(r+1,-k);
//差分的思想,x 位置上 +k,y+1的位置上-k
}
else if(flag == 'Q'){
ll l,r;
cin>>l>>r;
ll sum = query(r) - query(l-1);
cout<<sum<<endl;
}
}
return 0;
}