Luogu P1471 方差

题目传送门

开了十倍空间才过是什么鬼?该不会我线段树炸了吧……
细思恐极


平均数都会求,维护区间和,到时候除一下就好了。

方差的求法如下
(用的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;
}
原文地址:https://www.cnblogs.com/morslin/p/11854924.html