洛谷 P1471 方差

95 篇文章 1 订阅
75 篇文章 0 订阅

题目背景
滚粗了的HansBug在收拾旧数学书,然而他发现了什么奇妙的东西。
题目描述
蒟蒻HansBug在一本数学书里面发现了一个神奇的数列,包含N个实数。他想算算这个数列的平均数和方差。
输入输出格式
输入格式:
第一行包含两个正整数N、M,分别表示数列中实数的个数和操作的个数。
第二行包含N个实数,其中第i个实数表示数列的第i项。
接下来M行,每行为一条操作,格式为以下两种之一:
操作1:1 x y k ,表示将第x到第y项每项加上k,k为一实数。
操作2:2 x y ,表示求出第x到第y项这一子数列的平均数。
操作3:3 x y ,表示求出第x到第y项这一子数列的方差。
输出格式:
输出包含若干行,每行为一个实数,即依次为每一次操作2或操作3所得的结果(所有结果四舍五入保留4位小数)。
输入输出样例
输入样例#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
说明
这里写图片描述
样例说明:
这里写图片描述
数据规模:
这里写图片描述

//对于维护平均值这个东西,线段树是小菜一碟,随便你怎么搞
//然后对于方差;她有个公式的:
//S=[(a-Z)2+(b-Z)2+(c-Z)2+(d-Z)2+(e-Z)2...]/n(Z为平均数)
//S=[区间平方和-2*n*平均数^2+n*平均数^2]/n;
//S=[区间平方和-n*平均数2]/n;
//所以维护个平方和就好了;
//然后,平方和怎么区间加呢?
//她也有个公式:
//(a+p)^2+(b+p)^2+(c+p)^2+(d+p)^2+(e+p)^2  
//=以前平方和+(2*p*(Z*n)+n*p*p);
//综上所述,对于方差的维护只维护一个区间平方和就可以了 
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
#define MAXN 100050
#define INF 0
struct Segment_Tree{
    int l,r;
    double sum,sum_squ,p,lazy;
}tre[MAXN<<2];
inline void UpDate(int u){
    tre[u].sum=tre[u<<1].sum+tre[u<<1|1].sum;
    tre[u].sum_squ=tre[u<<1].sum_squ+tre[u<<1|1].sum_squ;
    tre[u].p=tre[u].sum/(tre[u].r-tre[u].l+1);
}
#define lc u<<1
#define rc u<<1|1
inline void PushDown(int u){
    tre[lc].lazy+=tre[u].lazy,tre[rc].lazy+=tre[u].lazy;

    int n=tre[lc].r-tre[lc].l+1; double z=tre[u].lazy;
    tre[lc].sum_squ+=n*(z*2*tre[lc].p+z*z);
    tre[lc].p+=z,tre[lc].sum+=n*z;

    n=tre[rc].r-tre[rc].l+1; z=tre[u].lazy;
    tre[rc].sum_squ+=n*(z*2*tre[rc].p+z*z);
    tre[rc].p+=z,tre[rc].sum+=z*n;
    tre[u].lazy=INF;
}

void Build(int u,int l,int r){
    tre[u].l=l,tre[u].r=r,tre[u].lazy=INF;
    if(l==r){
        scanf("%lf",&tre[u].sum);
        tre[u].sum_squ=tre[u].sum*tre[u].sum;
        tre[u].p=tre[u].sum;
        return ;
    }
    int Mid=l+r>>1;
    Build(u<<1,l,Mid),Build(u<<1|1,Mid+1,r);
    UpDate(u);
}

void Modify(int u,int l,int r,double k){
    if(l<=tre[u].l&&tre[u].r<=r){
        tre[u].lazy+=k;
        tre[u].sum+=(tre[u].r-tre[u].l+1)*k;
        tre[u].sum_squ+=(tre[u].r-tre[u].l+1)*(k*2*tre[u].p+k*k);
        tre[u].p+=k;
        return ;
    }
    if(tre[u].lazy!=INF) PushDown(u);
    int Mid=(tre[u].l+tre[u].r)>>1;
    if(r<=Mid) Modify(u<<1,l,r,k);
    else if(l>Mid) Modify(u<<1|1,l,r,k);
    else Modify(u<<1,l,Mid,k),Modify(u<<1|1,Mid+1,r,k);
    UpDate(u);
}

double query(int u,int l,int r,int opt){
    if(l<=tre[u].l&&tre[u].r<=r){
        if(opt==2) return tre[u].sum;
        if(opt==3) return tre[u].sum_squ;
    }
    if(tre[u].lazy!=INF) PushDown(u);
    int Mid=tre[u].l+tre[u].r>>1;
    if(l>Mid) return query(u<<1|1,l,r,opt);
    else if(r<=Mid) return query(u<<1,l,r,opt);
    else return query(u<<1,l,Mid,opt)+query(u<<1|1,Mid+1,r,opt);
}

int main(){
    int n,m;
    scanf("%d%d",&n,&m);
    Build(1,1,n);

    for(int l,r,opt,i=1;i<=m;++i){
        double k;
        scanf("%d%d%d",&opt,&l,&r);
        int kk=(r-l+1);
        if(opt==1) scanf("%lf",&k),Modify(1,l,r,k);
        if(opt==2)
            printf("%.4lf\n",query(1,l,r,opt)/(r-l+1));
        if(opt==3){
            double sum_square=query(1,l,r,opt);//该区间的平方和 
            double Average=query(1,l,r,2);//该区间的平均值 
            Average/=kk;
            printf("%.4lf\n",(sum_square-kk*Average*Average)/kk);
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

七情六欲·

学生党不容易~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值