方差公式展开
设存在一个序列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;
}