区间方差
P5142 区间方差
单点修改,区间查询。
更新很简单,直接赋值,然后更新(注意 \(y^2\) 可能爆 int
)。
对于询问,我们考虑完全平方公式 \((a_i-a)^2=a_i^2-2aa_i+a^2\),我们发现只需要维护区间平方和,区间和,平均数可以由区间和+逆元求出,然后就可以求了。
注意可能爆 int
的地方。
#include<cstdio>
#include<iostream>
using namespace std;
#define ls p<<1
#define rs p<<1|1
const int N=100010,M=4*N,mod=1e9+7;
int l[M],r[M],b[N],n,m,inv[N],ps[M],s[M];
typedef long long ll;
#define add(a,b) (a+=b)>=mod&&(a-=mod)
#define sub(a,b) (a-=b)<0&&(a+=mod)
#define up s[p]=s[ls],add(s[p],s[rs]),ps[p]=ps[ls],add(ps[p],ps[rs])
struct he{
int ps,s;
void operator+=(he A){
add(ps,A.ps);
add(s,A.s);
}
he(int _a=0,int _b=0):ps(_a),s(_b){}
};
void build(int p,int L,int R){
l[p]=L,r[p]=R;
if(L==R){
s[p]=b[L],ps[p]=1ll*b[L]*b[L]%mod;
return;
}
int mid=L+R>>1;
build(ls,L,mid),build(rs,mid+1,R);
up;
}
void update(int p,int x,int v){
if(l[p]==r[p]){
ps[p]=1ll*v*v%mod,s[p]=v;
return;
}
int mid=l[p]+r[p]>>1;
if(x<=mid)update(ls,x,v);
else update(rs,x,v);
up;
}
ll qpow(ll a,int b=mod-2){
ll res=1;
while(b){
if(b&1)res=res*a%mod;
a=a*a%mod;
b>>=1;
}
return res;
}
he query(int p,int L,int R){
if(L<=l[p]&&r[p]<=R)return he(s[p],ps[p]);
int mid=l[p]+r[p]>>1;
he ans;
if(L<=mid)ans=query(ls,L,R);
if(R>mid)ans+=query(rs,L,R);
up;
return ans;
}
int main(){
#ifndef ONLINE_JUDGE
freopen("1.in","r",stdin);
#endif
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin>>n>>m;
for(int i=1;i<=n;++i)cin>>b[i],inv[i]=i==1?1:1ll*(mod-mod/i)*inv[mod%i]%mod;
build(1,1,n);
for(int i=1;i<=m;++i){
int op,x,y;
ll len,in;
cin>>op>>x>>y;
in=inv[len=y-x+1];
if(op==1)update(1,x,y);
else{
auto[h,pfh]=query(1,x,y);
// cout<<h<<' '<<pfh<<'\n';
ll p=h*in%mod;
int ans=len*p%mod*p%mod;
add(ans,pfh);
sub(ans,p*h%mod*2%mod);
ans=ans*in%mod;
cout<<ans<<'\n';
// cout<<p<<' '<<ans<<"\n\n";
}
}
return 0;
}