假设一维数组为A[i]( i=1 ,2,…n ),则与它对应的树状数组C[i](i=1 ,2,…n)是这样定义的:
C1 = A1
C2 = A1 + A2
C3 = A3
C4 = A1 + A2 + A3 + A4
C5 = A5
C6 = A5 + A6
C7 = A7
C8 = A1 + A2 + A3 + A4 + A5 + A6 + A7 + A8
……
C16 = A1 + A2 + A3 + A4 + A5 + A6 + A7 + A8 + A9 + A10 + A11 + A12 + A13 + A14 + A15 + A16
……
一个有趣的性质
第C(x)管辖的区域为:2^k(k为二进制末尾的0的个数)
比如:
C(8) 8的二进制为1000 所以 k=3 2^3=8
int lowbit (int x)//计算C(x)展开的项数
{
return x&-x;
}
X即为数组的下标
意义:计算2^k的值,即C(x)管辖的区域
第二个函数:
int add (int x,int b)
{
while(x<=MAXN)
{
Tree(x)+=b;
x+=lowbit(x);
}
}
解释:
1:b是增量在树的结构中,每次增加b,即为修改了多少,是一个变量。修改了A(x)的值,会一直追溯到最终的父节点。
比如:A(2)增加了b,则该循环使其父节点依次增加b个单位。
C(2) C(4) C(8) 依次增加了b个单位。
2:x是数组的下标。
第三个函数:
int sum (int x)
{
int ret=0;
while(x>0)
{
ret+=tree[x];
x-=lowbit(x);
}
return ret;
}
解释:
1:求出范围a-b的和
Sum(b)-sum(a)即为所求。
求数列A[]的前n项和,只需找到n以前的所有最大子树,把其根节点的C加起来即可。
如:Sum(1)=C[1]=A[1];
Sum(2)=C[2]=A[1]+A[2];
Sum(3)=C[3]+C[2]=A[1]+A[2]+A[3];
Sum(4)=C[4]=A[1]+A[2]+A[3]+A[4];
Sum(5)=C[5]+C[4];
Sum(6)=C[6]+C[4];
Sum(7)=C[7]+C[6]+C[4];
Sum(8)=C[8];
一:区间修改,单点查询
题目:http://acm.hdu.edu.cn/showproblem.php?pid=1556
**
#include<cstdio>
#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include <cstdlib>
#include <cstdio>
#include <map>
#define lson l,m,i<<1
#define rson m+1,r,i<<1|1
#define lowbit(x) (x&(-x))
using namespace std;
const int MAXN = 100000;
const int LEN = MAXN + 100;
int tree[LEN];
int N;
void Add(int x,int p)//
{
while(x<=N)
{
tree[x] += p;
x += lowbit(x);
}
}
int Query(int x)
{
int sum = 0;
while(x)
{
sum += tree[x];
x -= lowbit(x);
}
return sum;
}
int main()
{
while(cin>>N&&N)
{
memset(tree,0,sizeof(tree));
for(int i = 1; i <= N; i++)
{
int a,b;
scanf("%d %d",&a,&b);
Add(a,1);
Add(b+1,-1);
}
for(int i = 1; i <= N; i++)
{
if(i>1)
printf(" ");
printf("%d",Query(i));
}
cout<<endl;
}
return 0;
}
**
二 :单点修改,区间查询
**
int low_bit(int x)
{
return x&(-x);
}
void add(int i,int c)
{
while(i<=n) //n是一共有多少点
{
a[i]+=c;
i+=low_bit(i);
}
}
int q(int i)
{
int ans=0;
while(i>0)
{
ans+=a[i];
i-=low_bit(i);
}
return ans;
}
int main()
{
add(i,c); // i是对那个点增加 c 是要增加的多少
//若查询 l--r 区间的和
ans=q(r)-q(l-1);
}
**
三 :区间修改,区间查询
**
略……………
部分转载自:https://blog.csdn.net/qq_24653023/article/details/46991325