树状数组 讲解
树状数组:(插点法 插线法)
最常见的一种用途是求一个数列的前N项和
比如说数组a[] 吧:把他转化一下存入树状数组c[] 中
如:
c[1]=a[1]
c[2]=a[1]+a[2]
c[3]=a[3]
c[4]=a[1]+a[2]+a[3]+a[4]
...........................
...........................
c[16]=a[1]+a[2]+....................+a[16]
也即c[n]管理着2^k个数 (k代表二进制n最后连续有多少个0) c[n]为这个连续2^k个数的最后一个
因此有 c[n]=a[n-2^k+1]+.....+a[n];
则:
2^k的简单求法有:
int lowbit(int n)
{
return x&(-x);
}
(一):求前N项和有:
1.sum=0;
2.if(n<=0) 则求的结果 sum+=c[n]; 否则转向第三步
3.n=n-lowbit(n); 转向第二步
(二):求:修改一个节点
eg:给第i个节点加上X
1.当i>n时,算法结束,否则转到第二步
2.c[i]+=x;,i+=lowbit(i);转到第一步
(三):以上两种情况都用到的时 树状数组的--插点法
下面是 树状数组--插线法:
比如:一个数组 操作:(i,j,k) 表示数组从第i项到第j项的值都加上k
经过几次操作之后 查询某一项的值
这个问题使用树状数组--插线法 速度非常快:
View Code
1 int lowbit(int x)
2 {
3 return x&(-x);
4 }
5
6 void add(int i,int k)// (i,j,k)这个操作 应用两次add: add(i-1,-k),add(j,k)
7 {
8 while(i>0)
9 {
10 c[i]+=k;
11 i-=lowbit(i);
12 }
13 }
14
15 int search(int n)// 经操作之后查询 第n项的值
16 {
17 int sum=0;
18 while(n<N)
19 {
20 sum+=c[n];
21 n+=lowbit(n);
22 }
23 return sum;
24 }
25
26
27 add(i-1,-k);//相当于把从第一项到第i-1项的值都减去k
28 add(j,k);//相当于把从第一项到第j项的的值都加上k
29 search(n);