洛谷 1471 方差

 

【题解】

  1,本题要求维护一个序列,支持区间加k,询问区间平均数和方差。

  2,询问平均数显然很好处理,在线段树上维护区间和sum以及区间长度len即可。

  3,方差的处理就相对麻烦一些。需要研究一下公式。

  我们先看看方差的公式:

  

  那就是1/n乘上这个式子:

  也就是区间平方和Sqr-区间和Sum的两倍+平均数Ave的平方乘区间长Len,所得结果再除以区间长Len

  那么我们在线段树上再维护一个区间平方和Sqr就好了

  4,在区间修改的时候,怎么维护Sqr呢?我们可以发现修改后的平方和为:

  (k是区间加上的数)

  展开式子就是:

  

  那就是原来的Sqr+原来的Sum乘k乘2+k的平方乘区间长Len

  这样,我们就可以解决这个问题了

#include<cstdio>
#include<algorithm>
#define N (800010)
#define ls (u<<1)
#define rs (u<<1|1)
#define mid ((a[u].l+a[u].r)>>1)
#define len(x) (a[x].r-a[x].l+1)
using namespace std;
int n,m,opt,x,y;
double del,sqr,sum;
struct tree{
	int l,r;
	double del,sum,sqr;
}a[N];
inline int read(){
	int k=0,f=1; char c=getchar();
	while(c<'0'||c>'9')c=='-'&&(f=-1),c=getchar();
	while('0'<=c&&c<='9')k=k*10+c-'0',c=getchar();
	return k*f;
}
inline void pushup(int u){
	a[u].sum=a[ls].sum+a[rs].sum;
	a[u].sqr=a[ls].sqr+a[rs].sqr;
}
inline void pushdown(int u){
	if(!a[u].del) return; double D=a[u].del; a[u].del=0;
	a[ls].del+=D; a[ls].sqr+=a[ls].sum*D*2+D*D*len(ls); a[ls].sum+=len(ls)*D;
	a[rs].del+=D; a[rs].sqr+=a[rs].sum*D*2+D*D*len(rs); a[rs].sum+=len(rs)*D;
}
void build(int u,int l,int r){
	a[u].l=l; a[u].r=r;
	if(l<r) build(ls,l,mid),build(rs,mid+1,r),pushup(u);
	else scanf("%lf",&a[u].sum),a[u].sqr=a[u].sum*a[u].sum;
}
void update(int u,int l,int r,double del){
	if(l<=a[u].l&&a[u].r<=r){
		a[u].sqr+=a[u].sum*del*2+del*del*len(u);
		a[u].sum+=len(u)*del;
		a[u].del+=del;
		return;
	}
	pushdown(u);
	if(l<=mid) update(ls,l,r,del);
	if(r>mid) update(rs,l,r,del);
	pushup(u);
}
void query(int u,int l,int r,double &sqr,double &sum){
	if(l<=a[u].l&&a[u].r<=r){
		sqr+=a[u].sqr; sum+=a[u].sum;
		return;
	}
	pushdown(u);
	if(l<=mid) query(ls,l,r,sqr,sum);
	if(r>mid) query(rs,l,r,sqr,sum);
}
int main(){
	n=read(); m=read();
	build(1,1,n);
	while(m--){
		if((opt=read())==1) x=read(),y=read(),scanf("%lf",&del),update(1,x,y,del);
		if(opt==2){
			sum=0; sqr=0;
			x=read(); y=read();
			query(1,x,y,sqr,sum);
			printf("%.4lf\n",1.0*sum/(y-x+1));
		}
		if(opt==3){
			sum=0; sqr=0;
			x=read(); y=read(); int l=y-x+1;
			query(1,x,y,sqr,sum);
			double ave=1.0*sum/l;
			//printf("sqr=%.4f sum=%.4f\n",sqr,sum);
			printf("%.4lf\n",(sqr-2*sum*ave+l*ave*ave)/l);
		}
	}
	return 0;
}

  

  

posted @ 2018-01-31 10:17  Driver_Lao  阅读(190)  评论(0编辑  收藏  举报