洛谷P5142
本题化完简单式子然后直接上线段树即可。
Description
给定一个序列,对其进行单点修改和求区间方差的操作。
注意输出方差时要以分数取模形式输出。
Solution
单点修改不多说,来看求区间方差。
假设我们要求的是 \([x,y]\) 的方差,也就是求:
\[{\frac{1}{y-x+1}\sum_{i=x}^y}(a_i-\overline a)^2
\]
化简以下(为了方便设 \(d=y-x+1\)):
\({=\frac{1}{d}\sum_{i=x}^y(a_i^2-2a_i\overline a+\overline a^2)}\)
\({=\frac{1}{d}[\sum_{i=x}^y(a_i^2-2a_i\overline a)]+\overline a^2}\)
\({=\frac{1}{d}\sum_{i=x}^ya_i^2}-\frac{1}{d}\sum_{i=x}^ya_i\cdot 2\overline a+\overline a^2\)
\({=\frac{1}{d}\sum_{i=x}^ya_i^2}-2\overline a^2+\overline a^2\)
\({=\frac{1}{d}\sum_{i=x}^ya_i^2}-\overline a^2\)
所以根据推导过程可以看出,我们需要维护的是区间平方和以及区间和。
然后就上线段树板子,最后按上面的公式求值,分数换成逆元即可。
Code
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#define maxn 510010
#define INF 0x3f3f3f3f
#define int long long
#define Mod 1000000007
using namespace std;
int n,m,a[maxn];
inline int read(){
int s=0,w=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-') w=-1;ch=getchar();}
while(ch>='0'&&ch<='9')s=(s<<1)+(s<<3)+ch-'0',ch=getchar();
return s*w;
}
int quickpow(int x,int y){
int ans=1;
while(y){
if(y&1)ans=(ans*x)%Mod;
x=(x*x)%Mod;y>>=1;
}
return ans;
}
namespace Seg{
#define ls x<<1
#define rs x<<1|1
#define f(x) x*x%Mod
int sum[maxn],fsum[maxn];
void pushup(int x){
sum[x]=(sum[ls]+sum[rs])%Mod;
fsum[x]=(fsum[ls]+fsum[rs])%Mod;
}
void build(int x,int l,int r){
if(l==r){
sum[x]=a[l]%Mod;
fsum[x]=f(a[l]);
return;
}
int mid=l+r>>1;
build(ls,l,mid);
build(rs,mid+1,r);
pushup(x);
}
void update(int x,int l,int r,int pos,int val){
if(l==r){
sum[x]=val%Mod;
fsum[x]=f(val);
return;
}
int mid=l+r>>1;
if(pos<=mid) update(ls,l,mid,pos,val);
else update(rs,mid+1,r,pos,val);
pushup(x);
}
int query(int x,int l,int r,int L,int R){
int ans=0;
if(L<=l&&R>=r) return sum[x]%Mod;
int mid=l+r>>1;
if(L<=mid) ans=(ans+query(ls,l,mid,L,R))%Mod;
if(R>=mid+1) ans=(ans+query(rs,mid+1,r,L,R))%Mod;
return ans%Mod;
}
int query2(int x,int l,int r,int L,int R){
int ans=0;
if(L<=l&&R>=r) return fsum[x]%Mod;
int mid=l+r>>1;
if(L<=mid) ans=(ans+query2(ls,l,mid,L,R))%Mod;
if(R>=mid+1) ans=(ans+query2(rs,mid+1,r,L,R))%Mod;
return ans%Mod;
}
int query3(int x,int l,int r,int L,int R,int val){
int ans=0;
if(L<=l&&R>=r) return fsum[x]%Mod;
int mid=l+r>>1;
if(L<=mid) ans=(ans+query2(ls,l,mid,L,R))%Mod;
if(R>=mid+1) ans=(ans+query2(rs,mid+1,r,L,R))%Mod;
return ans%Mod;
}
}
signed main(){
n=read();m=read();
for(int i=1;i<=n;i++)
a[i]=read();Seg::build(1,1,n);
for(int i=1,opt,fir,sec;i<=m;i++){
opt=read();fir=read();sec=read();
if(opt==1) Seg::update(1,1,n,fir,sec);
else{
int ni=quickpow(sec-fir+1,Mod-2);
int ave=Seg::query(1,1,n,fir,sec)*ni%Mod;
int ans=Seg::query2(1,1,n,fir,sec)*ni%Mod-f(ave);
printf("%lld\n",(ans%Mod+Mod)%Mod);
}
}
return 0;
}