线段树维护区间平均值和方差
滚粗了的 HansBug 在收拾旧数学书,然而他发现了什么奇妙的东西。
题目描述
蒟蒻 HansBug 在一本数学书里面发现了一个神奇的数列,包含 N 个实数。他想算算这个数列的平均数和方差。
输入格式
第一行包含两个正整数 N,M,分别表示数列中实数的个数和操作的个数。
第二行包含 N 个实数,其中第 i 个实数表示数列的第 i 项。
接下来 M 行,每行为一条操作,格式为以下三种之一:
操作 11:1 x y k
,表示将第 x 到第 y 项每项加上 k,k 为一实数。
操作 22:2 x y
,表示求出第 x 到第 y 项这一子数列的平均数。
操作 33:3 x y
,表示求出第 x 到第 y 项这一子数列的方差。
输出格式
输出包含若干行,每行为一个实数,即依次为每一次操作 22 或操作 33 所得的结果(所有结果四舍五入保留 44 位小数)。
输入输出样例
输入 #1
5 5 1 5 4 2 3 2 1 4 3 1 5 1 1 1 1 1 2 2 -1 3 1 5
输出 #1
3.0000 2.0000 0.8000
#include<iostream> #include<algorithm> using namespace std; const int maxn=1e6+100; double a[maxn]; struct node{ int l,r;//这个题不能维护区间平均值这样查询不对 double sum,p;///区间和,区间平方和 double lazy; double s; }t[maxn]; void push_up(int p){ t[p].sum=(t[2*p].sum+t[2*p+1].sum); t[p].p=(t[2*p].p+t[2*p+1].p); } void push_down(int p){ t[2*p].p+=1.0*(t[2*p].s*t[p].lazy*t[p].lazy+t[2*p].sum*2*t[p].lazy); t[2*p+1].p+=1.0*(t[2*p+1].s*t[p].lazy*t[p].lazy+t[2*p+1].sum*2*t[p].lazy); t[2*p].sum+=1.0*(t[p].lazy*t[2*p].s); t[2*p+1].sum+=1.0*(t[p].lazy*t[2*p+1].s); t[2*p].lazy+=t[p].lazy; t[2*p+1].lazy+=t[p].lazy; t[p].lazy=0; } void build(int p,int l,int r){ t[p].l=l; t[p].r=r; t[p].lazy=0; t[p].s=1.0*(t[p].r-t[p].l+1); if(l==r){ t[p].sum=a[l]; t[p].p=1.0*a[l]*a[l]; return ; } int mid=(t[p].l+t[p].r)/2; build(2*p,l,mid); build(2*p+1,mid+1,r); push_up(p); } void add(int p,int l,int r,double k){ if(t[p].l>=l&&t[p].r<=r){ t[p].p+=(1.0*t[p].s*k*k+2.0*t[p].sum*k); t[p].sum+=1.0*(t[p].s*k); t[p].lazy+=k; return ; } push_down(p); int mid=(t[p].l+t[p].r)/2; if(l<=mid){ add(2*p,l,r,k); } if(r>mid){ add(2*p+1,l,r,k); } push_up(p); } double querysum(int p,int l,int r){ if(t[p].l>=l&&t[p].r<=r){ return t[p].sum; } push_down(p); int mid=(t[p].l+t[p].r)/2; double ans=0; if(l<=mid){ ans+=querysum(2*p,l,r); } if(r>mid){ ans+=querysum(2*p+1,l,r); } return ans; } double queryp(int p,int l,int r){ if(t[p].l>=l&&t[p].r<=r){ return t[p].p; } push_down(p); int mid=(t[p].l+t[p].r)/2; double ans=0; if(l<=mid){ ans+=queryp(2*p,l,r); } if(r>mid){ ans+=queryp(2*p+1,l,r); } return ans; } int main(){ int n,m; cin>>n>>m; for(int i=1;i<=n;i++){ cin>>a[i]; } build(1,1,n); int op,x,y; double k; while(m--){ scanf("%d",&op); if(op==1){ scanf("%d%d%lf",&x,&y,&k); add(1,x,y,k); } if(op==2){ scanf("%d%d",&x,&y); printf("%.4lf\n",querysum(1,x,y)/(y-x+1)); } if(op==3){ scanf("%d%d",&x,&y); double sum=1.0*querysum(1,x,y); double eva=1.0*sum/(y-x+1); printf("%.4lf\n",(queryp(1,x,y)-2*eva*sum+eva*eva*(y-x+1))/(y-x+1)); // double change=querysum(1,x,y)/(y-x+1); // add(1,x,y,-change); // printf("%.4lf\n",queryp(1,x,y)/(y-x+1)); // add(1,x,y,change); } } }