P1471 方差
#算法/线段树
https://www.luogu.com.cn/problem/P1471
好久没刷算法题了,现在生疏了好多
求方差时:
假设求1-n的方差
res=((a1−div(a))2+(a2−(div(a))2+...+(an−div(a))2)/n
res=((a_1-div(a))^2+(a_2-(div(a))^2+...+(a_n-div(a))^2)/n
res=((a1−div(a))2+(a2−(div(a))2+...+(an−div(a))2)/n
分解
res=((a12+a22+...+an2)−2div(a)(a1+a2+..+an)+ndiv(a)2)/n
res=((a_1^2+a_2^2+...+a_n^2)-2div(a)(a_1+a_2+..+a_n)+ndiv(a)^2)/n
res=((a12+a22+...+an2)−2div(a)(a1+a2+..+an)+ndiv(a)2)/n
a1+a2+...+an=div(a)∗na_1+a_2+...+a_n=div(a)*na1+a2+...+an=div(a)∗n
res=(a12+a22+...+an2)/n−div(a)2
res=(a_1^2+a_2^2+...+a_n^2)/n-div(a)^2
res=(a12+a22+...+an2)/n−div(a)2
当我们对一个方差进行改变时
(a1+x)2+(a2+x)2+...(an+x)2=(a12+a22+...+an2)+2x(a1+a2+...+an)+nx2
(a_1+x)^2+(a_2+x)^2+...(a_n+x)^2=(a_1^2+a_2^2+...+a_n^2)+2x(a_1+a_2+...+a_n)+nx^2
(a1+x)2+(a2+x)2+...(an+x)2=(a12+a22+...+an2)+2x(a1+a2+...+an)+nx2
(a1+x)2+...+(an+x)2=(a12+a22+a32+...+an2)+2x(a1+a2+...+an)+nx2
(a_1+x)^2+...+(a_n+x)^2=(a_1^2+a_2^2+a_3^2+...+a_n^2)+2x(a_1+a_2+...+a_n)+nx^2
(a1+x)2+...+(an+x)2=(a12+a22+a32+...+an2)+2x(a1+a2+...+an)+nx2
在构建线段树时候,我们可以构建两个数组,一个存取总和,一个存取平方和,进行区间加减时,只需对两个数组进行变化即可.
[[线段树]]
代码
#include<iostream>#include<string>#include<stdio.h>using namespace std;const int N=1e6+10;typedef double db;db mark[N];db seg[N];db seg2[N];db a[N];#define lc p<<1#define rc p<<1|1void push_up(int p){seg[p]=seg[lc]+seg[rc];seg2[p]=seg2[lc]+seg2[rc];}void build(int p,int l,int r){if(l>=r){seg[p]=a[l];seg2[p]=a[l]*a[l];mark[p]=0;return;}int mid=l+r>>1;build(lc,l,mid);build(rc,mid+1,r);push_up(p);}bool inRange(int l,int r,int L,int R){if(l>=L&&r<=R)return true;return false;}bool outRange(int l,int r,int L,int R){if(r<L||l>R)return true;return false;}void push_down(int p,int len){if(mark[p]){//左区间的长度=l+r>>1,会比右区间多1个seg2[lc]+=2.0*mark[p]*seg[lc]+1.0*(len-len/2)*mark[p]*mark[p];seg[lc]+=mark[p]*(len-len/2);mark[lc]+=mark[p];//注意这里长度一定要写成(len/2),不能把括号忘了seg2[rc]+=2.0*mark[p]*seg[rc]+1.0*(len/2)*mark[p]*mark[p];seg[rc]+=mark[p]*(len/2);mark[rc]+=mark[p];mark[p]=0;}}void update(int p,int l,int r,int L,int R,db k){if(inRange(l,r,L,R)){seg2[p]=seg2[p]+2.0*k*seg[p]+(r-l+1)*k*k;seg[p]+=1.0*(r-l+1)*k;mark[p]+=k;return;}if(outRange(l,r,L,R)){return;}push_down(p,r-l+1);int mid=l+r>>1;update(lc,l,mid,L,R,k);update(rc,mid+1,r,L,R,k);push_up(p);}db query_sum(int p,int l,int r,int L,int R){if(inRange(l,r,L,R)){return seg[p];}if(outRange(l,r,L,R)){return 0;}push_down(p,r-l+1);int mid=l+r>>1;db sum=query_sum(lc,l,mid,L,R);sum+=query_sum(rc,mid+1,r,L,R);push_up(p);return sum;}db query_sum2(int p,int l,int r,int L,int R){if(inRange(l,r,L,R)){return seg2[p];}if(outRange(l,r,L,R)){return 0;}push_down(p,r-l+1);int mid=l+r>>1;db sum=query_sum2(lc,l,mid,L,R);sum+=query_sum2(rc,mid+1,r,L,R);push_up(p);return sum;}int main(void){int n,m;cin>>n>>m;for(int i=1;i<=n;i++)cin>>a[i];build(1,1,n);// cout<<query_sum(1,1,n,1,n)<<endl;for(int i=1;i<=m;i++){db opt,x,y,k;cin>>opt;if(opt==1){cin>>x>>y>>k;update(1,1,n,x,y,k);}else if(opt==2){cin>>x>>y;printf("%.4lf\n",query_sum(1,1,n,x,y)/(y-x+1));}else if(opt==3){cin>>x>>y;db sum=query_sum(1,1,n,x,y);db div=sum/(y-x+1);db sum2=query_sum2(1,1,n,x,y);// cout<<sum<<' '<<sum2<<endl;printf("%.4lf\n",sum2/(y-x+1)-(div*div));}}}