树状数组【洛谷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.