开了十倍空间才过是什么鬼?该不会我线段树炸了吧……
细思恐极
平均数都会求,维护区间和,到时候除一下就好了。
方差的求法如下
(用的Luogu的图片)
因为要维护一个平方,我们可以考虑使用van♂完全平方公式将它拆开,这样只用线段树维护区间和和区间平方和就可以了。
对于区间修改,同样使用完全平方公式。
要注意的一点是,修改时,要先修改平方和,再修改和,因为我们修改平方和时要用到区间和。
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#define ls p<<1
#define rs p<<1|1
#define mid ((l+r)>>1)
using namespace std;
struct zzz{
double sum,pf;
}tree[1000010<<2];
double tag[1000010<<2],a[1000010];
inline void up(int p){
tree[p].sum=tree[ls].sum+tree[rs].sum;
tree[p].pf=tree[ls].pf+tree[rs].pf;
}
void build(int l,int r,int p){
if(l==r){
tree[p].sum=a[l];
tree[p].pf=a[l]*a[l];
return ;
}
build(l,mid,ls); build(mid+1,r,rs);
up(p);
}
inline void down(int l,int r,int p){
//用完全平方公式修改平方和
tree[ls].pf+=2*tree[ls].sum*tag[p]+tag[p]*tag[p]*(mid-l+1);
tree[rs].pf+=2*tree[rs].sum*tag[p]+tag[p]*tag[p]*(r-mid);
//维护区间和
tree[ls].sum+=tag[p]*(mid-l+1);
tree[rs].sum+=tag[p]*(r-mid);
tag[ls]+=tag[p]; tag[rs]+=tag[p]; tag[p]=0;
}
void update(int l,int r,int p,int nl,int nr,double k){
if(l>=nl&&r<=nr){
tree[p].pf+=2*tree[p].sum*k+k*k*(r-l+1);
tree[p].sum+=k*(r-l+1);
tag[p]+=k;
return ;
}
down(l,r,p);
if(nl<=mid) update(l,mid,ls,nl,nr,k);
if(nr>mid) update(mid+1,r,rs,nl,nr,k);
up(p);
}
double query(int l,int r,int p,int nl,int nr){
double ans=0;
down(l,r,p);
if(l>=nl&&r<=nr) return tree[p].sum;
if(nl<=mid) ans+=query(l,mid,ls,nl,nr);
if(nr>mid) ans+=query(mid+1,r,rs,nl,nr);
return ans;
}
double query2(int l,int r,int p,int nl,int nr){
double ans=0;
down(l,r,p);
if(l>=nl&&r<=nr) return tree[p].pf;
if(nl<=mid) ans+=query2(l,mid,ls,nl,nr);
if(nr>mid) ans+=query2(mid+1,r,rs,nl,nr);
return ans;
}
int read(){
int k=0,f=1; char c=getchar();
for(;c<'0'||c>'9';c=getchar())
if(c=='-') f=-1;
for(;c>='0'&&c<='9';c=getchar())
k=k*10+c-48;
return k*f;
}
int main(){
int n=read(),m=read();
for(int i=1;i<=n;i++) scanf("%lf",&a[i]);
build(1,n,1);
for(int i=1;i<=m;i++){
int opt=read(),l=read(),r=read();
if(opt==1){
double k; scanf("%lf",&k);
update(1,n,1,l,r,k);
}
if(opt==2){
printf("%.4lf
",query(1,n,1,l,r)/(r-l+1));
}
if(opt==3){
double sum=query(1,n,1,l,r);
double pj=sum/(r-l+1);
double pf=query2(1,n,1,l,r);
printf("%.4lf
",(pf-2*sum*pj+pj*pj*(r-l+1))/(r-l+1));
}
}
return 0;
}