本渣战5,感谢start的博客,强烈推荐,树状数组3种不同的写法点击打开链接
(想学树状数组可以去看下神犇的这篇博客,很有帮助!本文写给看完那篇博客但还不是很理解成段更新的acmer)
此文只是阐述一下个人对树状数组+ 成段更新的个人理解。
一、 想学好树状数组,就一定要对这幅图很熟悉!
笔者指的熟悉是要至少不会对x+=x&(-x),x-=x&(-x),这两种 x 向 n 遍历和 x 向 0遍历的方式感到 疑惑(模糊)。
一定要明白 Cx 表示的是 1 - x 的 和阿 = = ,而且例如C7 = A[ 7 ] +C6 + C4.具体跟二进制有关(感觉会讲不清不讲了,读者自己体会下,大神请无视.......Orz)
二、
莫队算法,= =学过的应该比较好理解一些。
个人感觉成段更新 这个代码和莫队算法的思想很像,都是标记了 ( L , R) 不同的是两个辅助数组B ,C 。B :R -> 0 + C,L -> 0 - C: R - > N,+ C*R ;L->N -C*L;
//操作:
ADD_B(r, c); ADD_C(r, c);
if (l > 1) {ADD_B(l - 1, -c); ADD_C(l - 1, -c);}
至于 成段输出,可以输入时 另设一个A数组A[ i ] + = A[ i - 1];A[I]表示1-> I的和,至于区间 ( L , R) 的和原始的可以表示为A[ R ] - A[ L - 1 ];
然后再加上你对这个区间更新过后的值的和就OK了。
//A[m-1+x]-A[m-1]+ Sum(m-1+x)-Sum(m-1),这个就是题目要求的值
int sum_B(int x)
{
int sum = 0;
for(int i= x;i <= n; i+=i&(-i))sum+=B[i];
return sum;
}
int sum_C(int x )
{
int sum = 0;
for(int i= x;i > 0; i-=i&(-i))sum+=C[i];
return sum;
}
int Sum(int x)
{
if(x)return sum_B(x) * x + sum_C(x-1);
else return 0;
}
#include<stdio.h>
#include<string.h>
//快12点了注释就不打了。。= =
int A[100005];//A[I]表示1-I的士兵能力和
int B[100005];
int C[100005];
int n;
void add_B(int x,int c)
{
for(int i = x;i > 0; i-=i&(-i))B[i]+=c;
}
void add_C(int x,int c)
{
for(int i= x;i <= n; i+=i&(-i))C[i]+=x*c;
}
int sum_B(int x)
{
int sum = 0;
for(int i= x;i <= n; i+=i&(-i))sum+=B[i];
return sum;
}
int sum_C(int x )
{
int sum = 0;
for(int i= x;i > 0; i-=i&(-i))sum+=C[i];
return sum;
}
int Sum(int x)
{
if(x)return sum_B(x) * x + sum_C(x-1);
else return 0;
}
int main()
{
int x, k;
while(~scanf("%d%d%d",&n,&x,&k))
{
memset(C,0,sizeof(C));
memset(B,0,sizeof(B));
for(int i = 1;i <= n; i++)
{
scanf("%d",&A[i]);
if(i>1)A[i]+=A[i-1];
}
int m;
while(k--)
{
scanf("%d",&m);
printf("%d\n",A[m-1+x]-A[m-1]+ Sum(m-1+x)-Sum(m-1));
add_B(m-1+x,-1),add_C(m-1+x,-1);
if(m-1)add_B(m-1,1),add_C(m-1,1);
}
}
return 0;
}