传送门:洛谷 P1471 方差
算法分析:本题重在对方差的维护,平均值只要维护区间和
\(\bar{x}=\frac{\sum^n_{i=1}x_i}{n}\)
\(s^2=\frac{\sum^n_{i=1}(x_i-\bar{x})^2}{n}\)
\(\ \ \ \ =\frac{\sum^n_{i=1}(x_i^2-2x_i\bar{x}+\bar{x}^2)}{n}\)
\(\ \ \ \ =\frac{\sum^n_{i=1}x_i^2-\sum^n_{i=1}2x_i\bar{x}+\sum^n_{i=1}\bar{x}^2)}{n}\)
\(\ \ \ \ =\frac{\sum^n_{i=1}x_i^2-\sum^n_{i=1}2x_i\bar{x}+\sum^n_{i=1}\bar{x}^2)}{n}\)
\(\ \ \ \ =\frac{\sum^n_{i=1}x_i^2}{n}-\frac{\sum^n_{i=1}x_i\times2n\bar{x}}{n}+\frac{n\bar{x}^2}{n}\)
\(\ \ \ \ =\frac{\sum^n_{i=1}x_i^2}{n}-2\bar{x}^2+\bar{x}^2\)
\(\ \ \ \ =\frac{\sum^n_{i=1}x_i^2}{n}-\bar{x}^2\)
显然,只要维护区间平方和即可计算出方差\(s^2\)
那么如何维护区间平方和呢?
由完全平方公式,若把 \(x^2\) 更新为 \((x+\omega)^2\) ,则加上\((x+\omega)^2-x^2=x^2+2x\omega+\omega^2-x^2=2x\omega+\omega^2\)且优先进行平方的维护
#include<iostream>
#include<cstdio>
#include<cmath>
#define in(x) x=read()
#define mid ((l+r)>>1)
#define ls k<<1
#define rs k<<1 | 1
const int maxN=100000;
typedef int rd;
double v[4*maxN+1],sum1[4*maxN+1],sum2[4*maxN+1],z;
int n,m,x,y,op;
inline rd read();
void update(int,int,int,int,int,double);
double query_1(int,int,int,int,int);
double query_2(int,int,int,int,int);
void pushup(int),build(int,int,int);
void pushdown(int,int,int);
int main()
{
in(n); in(m); build(1,1,n);
for(int i=1;i<=m;i++)
{
in(op); in(x); in(y);
switch(op)
{
case 1:scanf("%lf",&z); update(1,1,n,x,y,z); break;
case 2:printf("%.4lf\n",query_1(1,1,n,x,y)/(y-x+1)); break;
case 3:
double sum_1=query_2(1,1,n,x,y)/(y-x+1);
double sum_2=query_1(1,1,n,x,y)/(y-x+1);
printf("%.4lf\n",sum_1-sum_2*sum_2);
}
}
return 0;
}
void build(int k,int l,int r)
{
if(l==r)
{
scanf("%lf",&sum1[k]);
sum2[k]=sum1[k]*sum1[k];
return;
}
build(ls,l,mid);
build(rs,mid+1,r);
pushup(k);
}
void pushdown(int k,int l,int r)
{
sum2[ls]+=2*v[k]*sum1[ls]+(mid-l+1)*v[k]*v[k];
sum2[rs]+=2*v[k]*sum1[rs]+(r-mid)*v[k]*v[k];
sum1[ls]+=(mid-l+1)*v[k];
sum1[rs]+=(r-mid)*v[k];
v[ls]+=v[k];
v[rs]+=v[k];
v[k]=0;
}
double query_1(int k,int l,int r,int ql,int qr)
{
if(ql<=l && r<=qr) return sum1[k];
if(v[k]) pushdown(k,l,r);
double ans=0;
if(ql<=mid) ans+=query_1(ls,l,mid,ql,qr);
if(qr>mid) ans+=query_1(rs,mid+1,r,ql,qr);
return ans;
}
double query_2(int k,int l,int r,int ql,int qr)
{
if(ql<=l && r<=qr) return sum2[k];
if(v[k]) pushdown(k,l,r);
double ans=0;
if(ql<=mid) ans+=query_2(ls,l,mid,ql,qr);
if(qr>mid) ans+=query_2(rs,mid+1,r,ql,qr);
return ans;
}
void update(int k,int l,int r,int ql,int qr,double w)
{
if(ql<=l && r<=qr)
{
sum2[k]+=2*w*sum1[k]+w*w*(r-l+1);
sum1[k]+=w*(r-l+1);
v[k]+=w;
return;
}
if(v[k]) pushdown(k,l,r);
if(ql<=mid) update(ls,l,mid,ql,qr,w);
if(qr>mid) update(rs,mid+1,r,ql,qr,w);
pushup(k);
}
void pushup(int k)
{
sum1[k]=sum1[ls]+sum1[rs];
sum2[k]=sum2[ls]+sum2[rs];
}
inline rd read()
{
rd num=0,f=1;
char ch=getchar();
while((ch<'0' || ch>'9') && ch!='-') ch=getchar();
if(ch=='-') {ch=getchar(); f=-1;}
while(ch>='0' && ch<='9')
{
num=num*10+ch-'0';
ch=getchar();
}
return num*f;
}