题目链接: http://poj.org/problem?id=3468
题目是对一个数组,支持两种操作
操作C:对下标从a到b的每个元素,值增加c;
操作Q:对求下标从a到b的元素值之和。
这道题也可以用线段树解,本文不做描述,下面分析如何用树状数组来解决这道题。
/*先把问题简化一点,因为 结果=初值+增量,所以,我们可以只对增量进行分析。然后,这种题有一个特点,就是如果对一般的一个操作C与操作查询前缀和的组合符合条件,那么无论进行多少次任意操作结果都是正确的。故 假设,先进行一次参数分别为 l,r,c 的操作C,再进行一次查询前缀和Si的操作(i 与l r的大小关系不定)。操作C之后,对Si,①当i<l时,Si=0,②当l<=i<r时,Si=c*(i-l+1),③当i>=r时,Si=c*(r-l+1)。要使情况①③满足比较简单,只需使add操作不在l左边进行,且对一树状数组的l和r分别进行+x+c*(r-l+1),-x的操作;而分析如何满足情况②,可以把Si看作是分布在直线y=c(x-l)=cx-cl上的一系列散点,易看出实现+cx的方法,就是在l执行add c的操作,在r执行add -c的操作,查询时查询sum()*x,而实现-cl的方法可以与上面“分别进行+x+c*(r-l+1),-x的操作”(引号中的x是不确定的)联系起来得出。故而任意Si都可以得出。*/
1 #include <cstdio> 2 3 typedef long long LL; 4 5 const int maxn =1e5+5; 6 LL a[2][maxn]; 7 LL psum[maxn]; 8 int n; 9 10 inline int lowbit(int x) 11 { 12 return x&-x; 13 } 14 void add(LL a[],int x,int d) 15 { 16 while(x<=n) 17 { 18 a[x]+=d; 19 x+=lowbit(x); 20 } 21 } 22 LL sum(LL a[],int x) 23 { 24 LL ret=0; 25 while(x) 26 { 27 ret+=a[x]; 28 x-=lowbit(x); 29 } 30 return ret; 31 } 32 33 LL query(int x) 34 { 35 return sum(a[1],x)*x+sum(a[0],x); 36 } 37 38 int main() 39 { 40 int q; 41 scanf("%d%d",&n,&q); 42 for(int i=1;i<=n;i++) 43 { 44 scanf("%I64d",&psum[i]); 45 psum[i]+=psum[i-1]; 46 } 47 char op[3]; 48 while(q--) 49 { 50 int l,r; 51 scanf("%s%d%d",op,&l,&r); 52 if(op[0]=='Q') 53 printf("%I64d ",query(r)-query(l-1)+psum[r]-psum[l-1]); 54 else 55 { 56 int c; 57 scanf("%d",&c); 58 add(a[1],l,c); 59 add(a[1],r,-c); 60 add(a[0],l,c*(-l+1)); 61 add(a[0],r,c*r); 62 } 63 } 64 }
//上面内容废弃,以下解析为2018.05.30更新
假设数组用a[]表示,定义辅助数组s[]、d[],其具体含义为
且s[]、d[]间有如下关系
原题中对a[]的区间修改,可以视为对d[]的单点修改,而s[]又可以由d[i]、i*d[i]的前缀和推导出来。且维护s1[]、s2[]较容易,因为每次操作都是对d[]进行单点修改。具体可以参考以下代码
#include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #include<functional> #include<iostream> #include<cmath> #include<cctype> #include<ctime> using namespace std; typedef long long LL; const int N=1e5+7; LL s1[N],s2[N]; int n,q; inline int lowbit(int x) { return x&-x; } void add(LL a[],int i,LL x) { while(i<=n) { a[i]+=x; i+=lowbit(i); } } LL sum(LL a[],int i) { LL ret=0; while(i) { ret+=a[i]; i-=lowbit(i); } return ret; } void Add(int i,LL x) { add(s1,i,x*i),add(s2,i,x); } LL Sum(int i) { return -sum(s1,i)+(i+1)*sum(s2,i); } int main() { scanf("%d%d",&n,&q); for(int i=1;i<=n;i++) { LL t; scanf("%lld",&t); Add(i,t),Add(i+1,-t); } while(q--) { int l,r; char op[3]; scanf("%s%d%d",op,&l,&r); if(op[0]=='Q') printf("%lld ",Sum(r)-Sum(l-1)); else { LL t; scanf("%lld",&t); Add(l,t),Add(r+1,-t); } } }