树状数组
lowbit函数:
lowbit(x)函数的实质是在求x在二进制表示下最后一个1的位置,也就是能整除x的最大2的幂次
举个例子,当x=6时,6能整除的最大2的幂次是2,所以lowbit(6)=2。
也可以从另一个方面来理解,我们来看一下lowbit函数的计算式:x&-x;
这个运算式为什么能计算x最右边一个1的位置呢?
我们来分解一下这个式子,依旧拿6来举例子,6的二进制表示是110,我们将其每一位都取反后变为001,再将这个数加上1得到010,然后我们再将这个数与110进行与运算,最后得到了010就是lowbit。
而对一个二进制数的每一位都取反再+1就刚好是计算机中补码的储存方式
所以很自然的就可以得到这个式子:x&-x;
树状数组模板题:
动态求连续区间和
给定 n 个数组成的一个数列,规定有两种操作,一是修改某个元素,二是求子数列 [a,b] 的连续和。
输入格式
第一行包含两个整数 n 和 m,分别表示数的个数和操作次数。
第二行包含 n 个整数,表示完整数列。
接下来 m 行,每行包含三个整数 k,a,b (k=0,表示求子数列[a,b]的和;k=1,表示第 a 个数加 b)。
数列从 1 开始计数。
输出格式
输出若干行数字,表示 k=0 时,对应的子数列 [a,b] 的连续和。
数据范围
1≤n≤100000
1≤m≤100000
1≤a≤b≤n
输入样例:
1 2 3 4 5 6 7 | 10 5 1 2 3 4 5 6 7 8 9 10 1 1 5 0 1 3 0 4 8 1 7 5 0 4 8 |
输出样例:
1 2 3 | 11 30 35 |
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int N = 1e5+10; int n,m; int a[N],tr[N]; int lowbit(int x) { return x&-x; } void add(int x,int y) { for(int i=x;i<=n;i+=lowbit(i))tr[i]+=y; } int query(int x) { int res=0; for(int i=x;i>0;i-=lowbit(i))res+=tr[i]; return res; } int main() { cin>>n>>m; for(int i=1;i<=n;i++)scanf("%d",&a[i]); for(int i=1;i<=n;i++)add(i,a[i]); for(int i=0;i<m;i++) { int k,z,x; scanf("%d%d%d",&k,&z,&x); if(k==0)printf("%d\n",query(x)-query(z-1)); else add(z,x); } return 0; } |