树状数组 讲解

树状数组:(插点法  插线法)
最常见的一种用途是求一个数列的前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);

 

posted @ 2012-02-12 13:04  知行执行  阅读(228)  评论(0编辑  收藏  举报