线段树上求平方和 和 差分。
sm1 : 区间和。
sm2 : 平方和。
len : 所求区间长度的逆元。
atr : 单点修改。
qry2 : 求 所求区间的 区间和 和 平方和。
S1 : 存 所求区间的 区间和。
S2 : 存 所求区间的 平方和。
#include<iostream>
#include<cstdio>
#define lo (nw<<1)
#define ro (nw<<1|1)
#define md (l+r>>1)
#define p 1000000007
using namespace std;
int n,m;
long long a[200010];
long long S1,S2;
struct Tree{
long long sm1;
long long sm2;
int siz;
}t[800010];
long long ksm(long long a){
int b=p-2;
long long ans=1;
while(b){
if(b&1) ans=(ans*a)%p;
b>>=1;
a=(a*a)%p;
}
return ans;
}
void upd(int nw){
t[nw].siz=t[lo].siz+t[ro].siz;
t[nw].sm1=(t[lo].sm1+t[ro].sm1)%p;
t[nw].sm2=(t[lo].sm2+t[ro].sm2)%p;
return ;
}
void bld(int nw,int l,int r){
if(l==r){
t[nw].sm1=a[l]%p;
t[nw].sm2=(a[l]*a[l])%p;
t[nw].siz=1;
return ;
}
bld(lo,l,md);
bld(ro,md+1,r);
upd(nw);
return ;
}
void atr(int nw,int l,int r,int x,long long z){
if(x==l&&x==r){
t[nw].sm2=(t[nw].sm2+2*z*t[nw].sm1%p+t[nw].siz*z*z%p)%p;
t[nw].sm1=(t[nw].sm1+z*t[nw].siz%p)%p;
return ;
}
if(x<=md) atr(lo,l,md,x,z);
else
if(x>md) atr(ro,md+1,r,x,z);
upd(nw);
return ;
}
void qry2(int nw,int l,int r,int x,int y){
if(x<=l&&r<=y){
S1=(S1+t[nw].sm1)%p;
S2=(S2+t[nw].sm2)%p;
return ;
}
if(x<=md) qry2(lo,l,md,x,y);
if(y>md) qry2(ro,md+1,r,x,y);
return ;
}
signed main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;++i){
scanf("%lld",&a[i]);
a[i]%=p;
}
bld(1,1,n);
int op,x,y;
long long k;
for(int i=1;i<=m;++i){
S1=S2=0;
scanf("%d%d",&op,&x);
if(op==1){
scanf("%lld",&k);
k%=p;
atr(1,1,n,x,k);
}
else if(op==2){
scanf("%d",&y);
qry2(1,1,n,x,y);
int len=ksm(y-x+1)%p;
printf("%lld\n",((S2*len%p-(S1*len%p)*(S1*len%p))%p+p)%p);
}
}
return 0;
}
好人有好报好人一生108胎,个个上梁山好人一生平安
谢谢!