P1471 方差 [ 线段树]

传送门

方差拆开

1/n\sum _{i=x}^y(xi-X)^2 =1/n\sum _{i=x}^yxi^2 -1/n*2X\sum _{i=x}^yxi+1/n*\sum _{i=x}^yX^2=1/n\sum _{i=x}^yxi^2-X^2

线段树维护区间和 , 区间平方和 , 修改时平方差一下就可以了

#include<bits/stdc++.h>
#define N 100050
#define len(x) (t[x].r-t[x].l+1)
using namespace std;
struct Node{int l,r; double v1,v2,tag;}t[N<<2];
int n,m; double a[N];
void Pushup(int x){
	t[x].v1 = t[x<<1].v1 + t[x<<1|1].v1;
	t[x].v2 = t[x<<1].v2 + t[x<<1|1].v2;
}
void build(int x,int l,int r){
	t[x].l = l , t[x].r = r;
	if(l==r){t[x].v1=a[l]; t[x].v2=a[l]*a[l]; return;}
	int mid = (l+r) >> 1;
	build(x<<1,l,mid); build(x<<1|1,mid+1,r);
	Pushup(x);
}
void Pushdown(int x){
	if(t[x].tag){
		t[x<<1].v2 += 2 * t[x<<1].v1 * t[x].tag;
		t[x<<1].v2 += t[x].tag * t[x].tag * len(x<<1);
		t[x<<1|1].v2 += 2 * t[x<<1|1].v1 * t[x].tag;
		t[x<<1|1].v2 += t[x].tag * t[x].tag * len(x<<1|1);
		t[x<<1].v1 += t[x].tag * len(x<<1);
		t[x<<1|1].v1 += t[x].tag * len(x<<1|1);
		t[x<<1].tag += t[x].tag;
		t[x<<1|1].tag += t[x].tag;
		t[x].tag = 0;
	}
}
void Update(int x,int L,int R,double val){
	if(L<=t[x].l && t[x].r<=R){
		t[x].v2 += 2 * t[x].v1 * val;
		t[x].v2 += val * val * len(x);
		t[x].v1 += val * len(x);
		t[x].tag += val;
		return;
	}
	Pushdown(x);
	int mid = (t[x].l+t[x].r) >> 1;
	if(L<=mid) Update(x<<1,L,R,val);
	if(R>mid) Update(x<<1|1,L,R,val);
	Pushup(x); 
}
double Quary(int x,int L,int R,int type){
	if(L<=t[x].l && t[x].r<=R){
		if(type==1) return t[x].v1;
		else return t[x].v2;
	}
	Pushdown(x);
	int mid = (t[x].l+t[x].r) >> 1; double ans=0;
	if(L<=mid) ans += Quary(x<<1,L,R,type);
	if(R>mid) ans += Quary(x<<1|1,L,R,type);
	return ans;
}
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++) scanf("%lf",&a[i]);
	build(1,1,n);
	for(int i=1;i<=m;i++){
		int op,x,y; scanf("%d%d%d",&op,&x,&y);
		if(op==1){
			double k; scanf("%lf",&k);
			Update(1,x,y,k);
		}
		if(op==2){
			double Sum=Quary(1,x,y,1);
			double len = (y-x+1) * 1.0;
			printf("%0.4lf\n",Sum/len);
		}
		if(op==3){
			double Sum = Quary(1,x,y,1);
			double Sum2 = Quary(1,x,y,2);
			double len = (y-x+1) * 1.0;
			double ans = Sum2 / len - (Sum/len * Sum/len);
			printf("%0.4lf\n",ans);
		}
	} return 0;
}

猜你喜欢

转载自blog.csdn.net/sslz_fsy/article/details/85109842