树状数组【洛谷3374】

【题目】

lowbit:一个数二进制中的最后一个1

int lowbit(int x){return x & -x;}

如 :100111010→10,1011000→1000

a[i]:不解释。

sum[i]:a[i - lowbit(i) + 1].....a[i]的和

xask(i,j):a[i].....a[j]的值,前缀和实现。

可以得到:①sum[i] = sum[i - lowbit(i)] + xask(i - lowbit(i) + 1,i)

ask(i):a[1]......a[i]的值

故有:

 

int ask(int x){
    int res = 0;
    for(int i = x;i > 0;i -= lowbit(i))
        res += sum[i];
    return res;
}

 

可以得到:a[i]...a[j]的值为ask(j) - ask(i - 1)

修改:②将a[i] 增加delta:while(i <= n)sum[i] += delta,i += lowbit(i);


 

证明:②:

表一:

i 1 2 3 4 5 6 7 8 9 10 11 12
sum[i]代表范围 1    1..2 3    1..4 5    5..6 7    1..8 9    9..10 11    9..12

 

 

 

 

 首先:lowerbit(a) < lowerbit(a + lowerbit(a))

证明:

   1  0  1  0  1  0  0

+                      1  0  0

------------------------------

          1  0  1  1  0  0  0

a加上lowerbit(a)后,最后一个“1”肯定没了,其后也不会多出“1”。

所以

int a = xxx;
int b = a + lowerbit(a);
则 a - lowerbit(a) < b - lowerbit(b)

所以,当你要把a[x]加上某一个值时,重复执行x += lowerbit(x),其sum[x]指示的范围始终包括i

这一点由表一可以验证。

故有以下代码:

void add(int w,int d){
    for(int i = w;i <= n;i += lowbit(i))
        sum[i] += d;
}

最后AC代码:

#include <cstdio>
#define N 1000001
int a[N],n,m,sum[N],tmp[N];
int lowbit(int x){return x & -x;}
int xask(int x,int y){return tmp[y] - tmp[x - 1];}
void creat(){for(int i = 1;i <= n;i++)sum[i] = xask(i - lowbit(i) + 1,i);}
void add(int w,int d){
    for(int i = w;i <= n;i += lowbit(i))
        sum[i] += d;
}
int ask(int x){
    int res = 0;
    for(int i = x;i > 0;i -= lowbit(i))
        res += sum[i];
    return res;
}
int main()
{
    tmp[0] = 0;
    scanf("%d %d",&n,&m);
    for(int i = 1;i <= n;i++)
        scanf("%d",&a[i]),tmp[i] = tmp[i - 1] + a[i];
    creat();
    for(int i = 1;i <= m;i++){
        int x,y,z;
        scanf("%d %d %d",&x,&y,&z);
        if(x == 1)add(y,z);
        else if(x == 2)printf("%d\n",ask(z) - ask(y - 1));
    }
    return 0;
}

 end.

posted @ 2018-03-18 20:01  应子帆  阅读(273)  评论(0编辑  收藏  举报