关于方差和区间平方和修改(线段树实现)

P1471方差

方差公式展开

设存在一个序列an
设d2为序列an的方差
在这里插入图片描述
即求方差的时候,只需求一个区间平方和和区间和即可
即线段树同时维护一个区间平方和和区间和即可

区间平方和修改

如何维护区间同时加上一个数x操作的区间平方和
在这里插入图片描述
即区间修改的时候加上(2k* 区间和+nk2)即可

如何用线段树维护???
令tree数组维护区间和
令tree2数组维护区间平方和
令lazy数组维护区间add的懒标记

仔细思考会发现一个小问题,pushdown和update的时候,是先计算tree2还是先计算tree1???
答:先算tree2

上代码
因为精度损失,故非AC代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const long long N=1e5+10;
double tree[N*4],tree2[N*4],lazy[N*4],a[N];

void pushup(int now) {
    
    
	tree[now]=tree[now*2]+tree[now*2+1];
	tree2[now]=tree2[now*2]+tree2[now*2+1];
}
void pushdown(int now,int l,int r,int mid) {
    
    
	if(lazy[now]) {
    
    
		tree2[now*2]+=2*lazy[now]*(tree[now*2])+(mid-l+1)*lazy[now]*lazy[now];
		tree2[now*2+1]+=2*lazy[now]*(tree[now*2+1])+(mid-l+1)*lazy[now]*lazy[now];
		//顺序问题 
		tree[now*2]+=(mid-l+1)*lazy[now];
		tree[now*2+1]+=(r-mid)*lazy[now];
		lazy[now*2]+=lazy[now];
		lazy[now*2+1]+=lazy[now];

		lazy[now]=0;
	}
}
void build(int now,int l,int r) {
    
    
	if(l==r) {
    
    
		tree[now]=a[l];
		tree2[now]=a[l]*a[l];
		return ;
	}
	int mid=(l+r)/2;
	build(now*2,l,mid);
	build(now*2+1,mid+1,r);
	pushup(now);
}
void update(int now,int l,int r,int ql,int qr,double k) {
    
    
	if(ql<=l&&r<=qr) {
    
    
		tree2[now]+=tree[now]*2*k+(r-l+1)*k*k;
		//顺序问题
		tree[now]+=(r-l+1)*k;
		lazy[now]+=k;

		return;
	}
	int mid=(l+r)/2;
	pushdown(now,l,r,mid);
	if(mid>=ql)update(now*2,l,mid,ql,qr,k);
	if(mid<qr)update(now*2+1,mid+1,r,ql,qr,k);
	pushup(now);
}
double querysum(int now,int l,int r,int ql,int qr) {
    
    
	if(ql<=l&&r<=qr) {
    
    
		return tree[now];
	}
	int mid=(l+r)/2;
	double ans=0;
	pushdown(now,l,r,mid);
	if(mid>=ql)ans+=querysum(now*2,l,mid,ql,qr);
	if(mid<qr)ans+=querysum(now*2+1,mid+1,r,ql,qr);
	return ans;
}
double querysum2(int now,int l,int r,int ql,int qr) {
    
    
	if(ql<=l&&r<=qr) {
    
    
		return tree2[now];
	}
	int mid=(l+r)/2;
	double ans=0;
	pushdown(now,l,r,mid);
	if(mid>=ql)ans+=querysum2(now*2,l,mid,ql,qr);
	if(mid<qr)ans+=querysum2(now*2+1,mid+1,r,ql,qr);
	return ans;
}
int main() {
    
    
	int n,q,x,y,key;
	double k;
	cin>>n>>q;
	for(int i=1; i<=n; i++)cin>>a[i];
	build(1,1,n);

	for(int i=1; i<=100; i++) {
    
    
		cin>>key;
		if(key==1) {
    
    
			cin>>x>>y>>k;
			update(1,1,n,x,y,k);
		}
		if(key==2) {
    
    
			cin>>x>>y;
			double sum=querysum(1,1,n,x,y);
			double ave=sum/(y-x+1);
			printf("%.4lf\n",ave);
		}
		if(key==3) {
    
    
			cin>>x>>y;
			double sum=querysum(1,1,n,x,y);
			double ave=sum/(y-x+1);
			double sum2=querysum2(1,1,n,x,y);
			double ans=sum2/(y-x+1)-ave*ave;
			printf("%.4lf\n",ans);
		}
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_43602607/article/details/109466976