题目大意
给出一个序列a,和一些区间求和询问,称作一些函数。有很多个操作,修改a[i]的值,询问一个区间内函数和,就是询问一些区间询问的和。
解题思路
考虑一个只询问函数的情况,我们可以用分块维护块内的前缀和,块之间的前缀和,修改时o(sqrt(n))即可解决,询问时o(1)即可解决.
考虑将函数也分块,维护每个块内所有函数和对a[i]的权,即要统计几次。这样我们可以o(1)解决修改对一个块的影响,询问时可以o(sqrt(n))解决。对于零散的单个函数可以o(1)解决,这样就可以o(n sqrt(n))解决问题。
code
using namespace std;
int const Mxn=5*1e4;
int N,Q,Size,Block,A[Mxn+9],L[Mxn+9],R[Mxn+9],Begin[Mxn+9],D[500][Mxn+9];
LL B[Mxn+300],C[Mxn+9],E[Mxn+9];
LL Calc(int X){
return -B[L[X]-1]*(L[X]%Size!=1)+(((R[X]-1)/Size)?C[(R[X]-1)/Size-1]:0)-(((L[X]-1)/Size)?C[(L[X]-1)/Size-1]:0)+B[R[X]];
}
int main(){
//freopen("d.in","r",stdin);
//freopen("d.out","w",stdout);
scanf("%d",&N);Size=sqrt(N);Block=(N-1)/Size;
Fo(i,1,N){
scanf("%d",&A[i]);Begin[i]=(i-1)/Size*Size+1;
Fo(j,i,Begin[i]+Size-1)B[j]+=A[i];
Fo(j,(i-1)/Size,Block)C[j]+=A[i];
}
Fo(i,1,N){
scanf("%d%d",&L[i],&R[i]);
D[(i-1)/Size][L[i]]++;
D[(i-1)/Size][R[i]+1]--;
}
Fo(i,0,Block)Fo(j,1,N)E[i]+=1ll*A[j]*(D[i][j]+=D[i][j-1]);
scanf("%d",&Q);
int Ch,X,Y,Add;
Fo(i,1,Q){
scanf("%d%d%d",&Ch,&X,&Y);
if(Ch==1){
Add=Y-A[X];
Fo(j,X,Begin[X]+Size-1)B[j]+=Add;
Fo(j,(X-1)/Size,Block)C[j]+=Add;
Fo(j,0,Block)E[j]+=1ll*D[j][X]*Add;
A[X]=Y;
}else{
LL Ans=0;int Mx=(Y-1)/Size-1;
if(Begin[X]!=Begin[Y]){
Fo(j,(X-1)/Size+1,Mx)Ans+=E[j];
Fo(j,X,Begin[X]+Size-1)Ans+=Calc(j);
Fo(j,Begin[Y],Y)Ans+=Calc(j);
}else{
Fo(j,X,Y)Ans+=Calc(j);
}
printf("%lld\n",Ans);
}
}
return 0;
}