bzoj3155Preprefix sum
题意:
询问一个数组前缀和数组的前缀和,支持单点修改。
题解:
SSi=sigma(i,1,n)(n-i+1)*ai=(n+1)*Si-sigma(i,1,n)i*ai。然后就只要用树状数组维护ai和i*ai的前缀和就行了。
代码:
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #define inc(i,j,k) for(int i=j;i<=k;i++) 5 #define maxn 100010 6 #define lb(x) x&-x 7 #define ll long long 8 using namespace std; 9 10 ll v[maxn][2],sm[maxn][2]; int n,m; char s[10]; 11 inline int read(){ 12 char ch=getchar(); int f=1,x=0; 13 while(ch<'0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();} while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar(); 14 return f*x; 15 } 16 void update(int x,ll val,bool b){while(x<=n)sm[x][b]+=val,x+=lb(x);} 17 ll query(int x,bool b){ll q=0; while(x)q+=sm[x][b],x-=lb(x); return q;} 18 int main(){ 19 n=read(); m=read(); 20 inc(i,1,n)v[i][0]=(ll)read(),v[i][1]=(ll)i*v[i][0],update(i,v[i][0],0),update(i,v[i][1],1); 21 inc(i,1,m){ 22 scanf("%s",s); 23 if(s[0]=='Q'){int a=read(); printf("%lld\n",query(a,0)*(a+1)-query(a,1));} 24 if(s[0]=='M'){ 25 int a=read(); ll b=(ll)read(); 26 update(a,b-v[a][0],0); v[a][0]=b; update(a,b*a-v[a][1],1); v[a][1]=b*a; 27 } 28 } 29 return 0; 30 }
20160630