线段树维护区间平均值和方差

传送门

滚粗了的 HansBug 在收拾旧数学书,然而他发现了什么奇妙的东西。

题目描述

蒟蒻 HansBug 在一本数学书里面发现了一个神奇的数列,包含 N 个实数。他想算算这个数列的平均数和方差。

输入格式

第一行包含两个正整数 N,M,分别表示数列中实数的个数和操作的个数。

第二行包含 N 个实数,其中第 i 个实数表示数列的第 i 项。

接下来 M 行,每行为一条操作,格式为以下三种之一:

操作 11:1 x y k ,表示将第 x 到第 y 项每项加上 kk 为一实数。
操作 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);
        }
    }
} 

 

posted @ 2021-04-11 21:49  lipu123  阅读(184)  评论(0编辑  收藏  举报