BIT—树状数组
先学术一波:树状数组Binary Indexed Tree其实昨天我补线段树白书的时候以为白书的代码方法和树状数组有关,不比计蒜客那gb复杂,然后事实是我想多了 那个白书我看到的还是线段树的求和,只是单纯的引出树状数组的求和,那就只能硬着头皮搞下去了:
上理解:
我觉着吧,树状数组就是线段树的变形
来我们先回看一遍线段树的图
:
RT 然后树状数组提出的一个问题就是既然是求和,那么我们其实可以将每一个父亲节点到两个左右子节点的两条连线删去一条;比如:
你看 这就是变成了一个树状数组,我一开始就特别纳闷这他妈咋回事?后来看见书上说 假如现在我们需要用到节点二区间的部分和,我们可以拿节点0的部分和-节点一的部分和我才明白。
哦对了 计蒜客还说了一个所谓的“有趣的”性质,对二进制不熟悉的我看的一头雾水
说是:设节点编号为x,那么该节点区间为2^k(k为x二进制末尾0的个数)个元素,因为这个区间最后一个元素必为Ax,所有很明显,Cn=A(n-2^k+1)+...+An;
而计算这个2^k,也就是最低位的1,可以这样写:
int lowbit(int x){
return x&(x^(x-1));}
利用机器补码特性也可以写成:
int lowbit (int x){
return x&-x;}
就说了这些,恕我直言看完我是:????黑人问号????
但是大概是懂了意思,就是要找出x的最低位1,然后用来使用上面那条性质
然后又是分别介绍了一通查询和修改,说实话对二进制不熟有点难受,但是理解这个意思还是可以的
于是我还是先上计蒜客的魔板代码吧(魔 滑稽):
计蒜客:
#include <iostream>
using namespace std;
const int MAX_N=10010;
int C[MAX_N];
int n;
int lowbit(int x){
return x&(-x);
}
int getsum(int x)
{
int res=0;
for(;x;x-=lowbit(x)){
res+=C[x];
}
return res;
}
void change(int x,int c)
{
for(;x<=n;x+=x&(-x)){
C[x]+=c;
}
}
int main() {
cin>>n;
for(int i=1;i<=n;i++)
{
int d;
cin>>d;
change(i,d);
}
for(int i=1;i<=n;i++)
{
cout<<getsum(i)<<" ";
}
return 0;
}
挑战:
(只写主要的了)
// [1,n];
int bit[maxn+1],n;
int sum(int i)
{
int s=0;
while(i>0){
s+=bit[i];
i-=i&-i;//这里也可以写成:i=i&(i-1);
}
return s;
}
void add(int i,int x)
{
while(i<=n)
{
bit[i]+=x;
i+=i&-i;
}
}
如图了:
对比明显挑战的更让我舒服,简洁,实在不行也好背啊(逃