给一个初始值全为0的数列a1,a2,...,an.

给定 i,求a1+a2+..+ai.

给定i,x 执行ai+x;


图不好看见谅:

如图所示,1节点维护的是a1本身的和

2节点维护的是 a1到a2 的和

3节点维护的是a3的和

4节点维护的是a1到a4 的和

为啥会有些节点维护的值的个数不同呢?

很简单 ,就是看最后一个1的位置,2:二进制0010 最后一个1是第2个位置所以维护2的2-1次方个值。4:0100维护2的3-1次方个值。



加法,把有维护自己的值都加上X就行了

加法:例子在a3上+X就是在3节点上+X,4节点+X,8节点+X。看一眼上图,就知道,就是按箭头一个个向上节点转移。

怎么实现这种转移呢?

3的二进制是0011.4是 0100,8是1000.

就是把加上最后一个1所在位置的值,0011 +0001(最后一个位置是最后一个)=0100;

0100+0100(最后一个1位置是第3个)=1000;

以此类推,在a5也是一样,0101+0001=0110(6);

0110+0010=1000(8);

怎么实现,就是i+=i&-i;

i&-i可以把自己最后一个1的位置算出来,怎么来的就自己去百度吧。

 

 

求和:比如 前5个的和,就是(1到4)+5 也就是4节点加5节点的和。

前7个的和就是7+(5到6)+(1到4)的和,也就是4节点加6节点加7节点的和。

 

至于怎么实现呢如果细心的话不难发现,其实就是从最后一个1慢慢一个个变成0的节点全加上  如 7的二进制是0111

前7个的和就是 0111+ 0110+0100

前 5(0101)个的和  0101 +0100

按位运算就是 i-=i&-i.

代码非常简单。

复杂度 O(log N);

#include<bits/stdc++.h>
using namespace std;
const int maxn=1<<15;
int bit[maxn+1],n;
int sum(int i)
{
    int s=0;
    while(i>0)
    {
        s +=bit[i];
        i-=i&-i;
    }
    return s;
}
void add(int i,int x)
{
    while(i<=n)
    {
        bit[i]+=x;
        i+=i&-i;
    }
}