Luogu P1471 【方差】题解

我们可以设
$ sum1[n]=a[1]+a[2]+\cdots+a[n] $
$ sum2[n]=a[1]^{2}+a[2]^{2}+\cdots+a[n]^{2} $

那么我们就可以表示出方差了

方差公式展开:

$ \frac {\sum_{i=1}^{n} (a[i]-\overline{a})^{2} } {n} $

$ = \frac {(a[1]-\overline{a})^{2} + (a[2]-\overline{a})^{2} + \cdots +(a[n]-\overline{a})^{2} } {n} $

$ = \frac{a[1]^{2} + a[2]^{2} + \cdots +a[n]^{2}- 2 \overline{a}(a[1] + a[2] + \cdots +a[n] ) +n\overline{a}^{2} }{n} $

$ = \frac{a[1]^{2} + a[2]^{2} + \cdots +a[n]^{2} }{n} - 2\overline{a} \frac{a[1]+a[2]+\cdots+a[n]}{n}+\overline{a}^{2} $

$ = \frac{a[1]^{2} + a[2]^{2} + \cdots +a[n]^{2} }{n} - 2\overline{a}^{2}+\overline{a}^{2} $

$ = \frac{a[1]^{2} + a[2]^{2} + \cdots +a[n]^{2} }{n} - \overline{a}^{2} $

$ = \frac{sum2[n]}{n} - \overline{a}^{2} $

至于修改也很简单了

区间加展开:

$ \sum_{i=1}^{n} (a[i]+x)^{2} $

$ = (a[1]+x)^{2} + (a[2]+x)^{2} + \cdots +(a[n]+x)^{2} $

$ = a[1]^{2} + a[2]^{2} + \cdots +a[n]^{2}+ 2 x(a[1] + a[2] + \cdots +a[n] ) +nx^{2} $

$ = sum2[n]+ 2 x $ $sum1[n] +nx^{2} $

于是就可以用带lazy的线段树来解决

*注意:优先级应该是要先处理sum2,再处理sum1

丑陋的代码如下:

#include<cstdio>

#define ll long long
#define lc(x) (x<<1)
#define rc(x) (x<<1|1)

const ll maxn=100000;

double sum1[(maxn<<2)+5],sum2[(maxn)<<2+5];
double lazy[(maxn<<2)+5];

inline void pushup(ll v){
    sum1[v]=sum1[lc(v)]+sum1[rc(v)];
    sum2[v]=sum2[lc(v)]+sum2[rc(v)];
}

inline void pushdown(ll v,ll l,ll r){
    if(lazy[v]){
        ll mid=l+r>>1;
        lazy[lc(v)]+=lazy[v];
        lazy[rc(v)]+=lazy[v];
        sum2[lc(v)]+=2.0*lazy[v]*sum1[lc(v)]+(mid-l+1)*lazy[v]*lazy[v];
        sum2[rc(v)]+=2.0*lazy[v]*sum1[rc(v)]+(r-mid)*lazy[v]*lazy[v];
        sum1[lc(v)]+=lazy[v]*(mid-l+1);
        sum1[rc(v)]+=lazy[v]*(r-mid);
        lazy[v]=0;
    }
}

void update(ll v,ll l,ll r,ll left,ll right,double add){
    if(left<=l&&r<=right){lazy[v]+=add,sum2[v]+=2.0*sum1[v]*add+(r-l+1)*add*add,sum1[v]+=add*(r-l+1);return;}
    ll mid=l+r>>1;
    pushdown(v,l,r);
    if(left<=mid)update(lc(v),l,mid,left,right,add);
    if(right>mid)update(rc(v),mid+1,r,left,right,add);
    pushup(v);
}

double query_a(ll v,ll l,ll r,ll left,ll right){
    if(left<=l&&r<=right){return sum1[v];}
    ll mid=l+r>>1;double ans=0;
    pushdown(v,l,r);
    if(left<=mid)ans+=query_a(lc(v),l,mid,left,right);
    if(right>mid)ans+=query_a(rc(v),mid+1,r,left,right);
    return ans;
}

double query_b(ll v,ll l,ll r,ll left,ll right){
    if(left<=l&&r<=right){return sum2[v];}
    ll mid=l+r>>1;double ans=0;
    pushdown(v,l,r);
    if(left<=mid)ans+=query_b(lc(v),l,mid,left,right);
    if(right>mid)ans+=query_b(rc(v),mid+1,r,left,right);
    return ans;
}

ll n,m;
int main(){
    scanf("%lld%lld",&n,&m);
    for(ll i=1;i<=n;i++){
        double p;scanf("%lf",&p);
        update(1,1,n,i,i,p);
    }
    for(ll i=1;i<=m;i++){
        ll op,l,r;scanf("%lld%lld%lld",&op,&l,&r);
        if(op==1){
            double k;scanf("%lf",&k);
            update(1,1,n,l,r,k);
        }
        if(op==2){
            double ans=(double)query_a(1,1,n,l,r)/(r-l+1);
            printf("%.4lf\n",(double)ans);
        }
        if(op==3){
            double ans=(double)query_a(1,1,n,l,r)/(r-l+1);
            double ans1=(double)query_b(1,1,n,l,r)/(r-l+1);
            double ans2=(double)ans1-(double)ans*ans;
            printf("%.4lf\n",(double)ans2);
        }
    }
    return 0;
}

转载于:https://www.cnblogs.com/Railgunforever/p/9965829.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值