题目大意
给定一个序列要求支持单点修改、区间修改、区间求和、区间求方差。
计算方差
我们来看看如何解决方差。
设sum为平方和,num为和。
s2=1n[(a1−numn)2+...(an−numn)2]
s2=1n(sum+num2n−2∗num2n)
s2=1n(sum−num2n)
发现方差只与平方和与和有关,因此我们可以开一颗线段树来维护这两个因素。
至于区间修改,同平方和那题。
参考程序
#include<cstdio>
#include<iostream>
#include<cstdlib>
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
typedef long long ll;
typedef double db;
const ll maxn=100000+10;
ll sum[maxn*4],num[maxn*4],add[maxn*4];
ll i,j,k,l,t,n,m;
db x,y,z,ans;
void change(ll p,ll l,ll r,ll a,ll b,ll x){
if (l==a&&r==b){
sum[p]=sum[p]+x*x*(r-l+1)+2*num[p]*x;
num[p]=num[p]+x*(r-l+1);
add[p]=add[p]+x;
return;
}
ll mid=(l+r)/2;
if (add[p]){
sum[p*2]=sum[p*2]+add[p]*add[p]*(mid-l+1)+2*num[p*2]*add[p];
num[p*2]=num[p*2]+add[p]*(mid-l+1);
add[p*2]=add[p*2]+add[p];
sum[p*2+1]=sum[p*2+1]+add[p]*add[p]*(r-mid)+2*num[p*2+1]*add[p];
num[p*2+1]=num[p*2+1]+add[p]*(r-mid);
add[p*2+1]=add[p*2+1]+add[p];
add[p]=0;
}
if (b<=mid) change(p*2,l,mid,a,b,x);
else if (a>mid) change(p*2+1,mid+1,r,a,b,x);
else{
change(p*2,l,mid,a,mid,x);
change(p*2+1,mid+1,r,mid+1,b,x);
}
sum[p]=sum[p*2]+sum[p*2+1];
num[p]=num[p*2]+num[p*2+1];
}
ll getsum(ll p,ll l,ll r,ll a,ll b){
if (l==a&&r==b) return sum[p];
ll mid=(l+r)/2;
if (add[p]){
sum[p*2]=sum[p*2]+add[p]*add[p]*(mid-l+1)+2*num[p*2]*add[p];
num[p*2]=num[p*2]+add[p]*(mid-l+1);
add[p*2]=add[p*2]+add[p];
sum[p*2+1]=sum[p*2+1]+add[p]*add[p]*(r-mid)+2*num[p*2+1]*add[p];
num[p*2+1]=num[p*2+1]+add[p]*(r-mid);
add[p*2+1]=add[p*2+1]+add[p];
add[p]=0;
}
if (b<=mid) return getsum(p*2,l,mid,a,b);
else if (a>mid) return getsum(p*2+1,mid+1,r,a,b);
else return getsum(p*2,l,mid,a,mid)+getsum(p*2+1,mid+1,r,mid+1,b);
}
ll getnum(ll p,ll l,ll r,ll a,ll b){
if (l==a&&r==b) return num[p];
ll mid=(l+r)/2;
if (add[p]){
sum[p*2]=sum[p*2]+add[p]*add[p]*(mid-l+1)+2*num[p*2]*add[p];
num[p*2]=num[p*2]+add[p]*(mid-l+1);
add[p*2]=add[p*2]+add[p];
sum[p*2+1]=sum[p*2+1]+add[p]*add[p]*(r-mid)+2*num[p*2+1]*add[p];
num[p*2+1]=num[p*2+1]+add[p]*(r-mid);
add[p*2+1]=add[p*2+1]+add[p];
add[p]=0;
}
if (b<=mid) return getnum(p*2,l,mid,a,b);
else if (a>mid) return getnum(p*2+1,mid+1,r,a,b);
else return getnum(p*2,l,mid,a,mid)+getnum(p*2+1,mid+1,r,mid+1,b);
}
int main(){
scanf("%lld%lld",&n,&m);
fo(i,1,n){
scanf("%lld",&j);
change(1,1,n,i,i,j);
}
fo(i,1,m){
scanf("%lld",&t);
if (!t){
scanf("%lld%lld",&j,&k);
change(1,1,n,j,j,k);
}
else if (t==1){
scanf("%lld%lld%lld",&j,&k,&l);
change(1,1,n,j,k,l);
}
else if (t==2){
scanf("%lld%lld",&j,&k);
printf("%lld\n",getnum(1,1,n,j,k));
}
else{
scanf("%lld%lld",&j,&k);
l=getnum(1,1,n,j,k);t=getsum(1,1,n,j,k);
x=l;y=t;z=(k-j+1);
ans=(double)y*z;
ans=(double)(ans-(double)x*x);
ans=(double)ans/((double)z*z);
printf("%.4lf\n",ans);//有spj,为了防误差这里保留4位。
}
}
return 0;
}