洛谷P1471 方差(线段树lazy维护区间平均数和区间方差)

题意:传送门
题解:三种操作:一是区间加,使用lazy操作即可完成,而是平均数,使用区间加维护,三是区间方差,将公式展开,发现 s 2 = 1 n ∗ ( ∑ i = x i = y a i 2 − 2 ∗ a ‾ ∗ ∑ i = x i = y a i + ( y − x + 1 ) ∗ a ‾ ) s^2=\frac{1}{n}*(\sum_{i=x}^{i=y}a_{i}^2-2*\overline{a}*\sum_{i=x}^{i=y}a_{i}+(y-x+1)*\overline{a}) s2=n1(i=xi=yai22ai=xi=yai+(yx+1)a),所以再多维护一个区间平方和即可。

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
int n,m,t,x,y;
double z;
struct data{
    int l,r;
    double sum,ssum,add;
}tree[maxn<<2];
void update(int k)
{
    tree[k].sum=tree[k<<1].sum+tree[k<<1|1].sum;
    tree[k].ssum=tree[k<<1].ssum+tree[k<<1|1].ssum;
}
void pushdown(int k,int x)
{
    if(tree[k].add){
        tree[k<<1].ssum+=2*tree[k].add*tree[k<<1].sum+tree[k].add*tree[k].add*(x-x/2);
        tree[k<<1|1].ssum+=2*tree[k].add*tree[k<<1|1].sum+tree[k].add*tree[k].add*(x/2);
        tree[k<<1].sum+=(x-x/2)*tree[k].add;
        tree[k<<1|1].sum+=(x/2)*tree[k].add;
        tree[k<<1].add+=tree[k].add;
        tree[k<<1|1].add+=tree[k].add;
        tree[k].add=0;
    }
}
void build(int k,int s,int t)
{
    tree[k].l=s;tree[k].r=t;
    if(s==t){scanf("%lf",&tree[k].sum);tree[k].ssum=tree[k].sum*tree[k].sum;return ;}
    int mid=(s+t)>>1;
    build(k<<1,s,mid);
    build(k<<1|1,mid+1,t);
    update(k);
}
void change(int k,int p,int q,double y)
{
    int l=tree[k].l,r=tree[k].r;
    if(l==p&&r==q){
        tree[k].ssum+=2*y*tree[k].sum+(r-l+1)*y*y;
        tree[k].sum+=(r-l+1)*y;
        tree[k].add+=y;
        return ;
    }
    pushdown(k,r-l+1);
    int mid=(l+r)>>1;
    if(q<=mid)change(k<<1,p,q,y);
    else if(p>mid)change(k<<1|1,p,q,y);
    else{
        change(k<<1,p,mid,y);
        change(k<<1|1,mid+1,q,y);
    }
    update(k);
}
double ask1(int k,int p,int q)
{
    int l=tree[k].l,r=tree[k].r;
    if(l==p&&r==q)return tree[k].sum;
    pushdown(k,r-l+1);
    int mid=(l+r)>>1;
    if(q<=mid)return ask1(k<<1,p,q);
    else if(p>mid)return ask1(k<<1|1,p,q);
    else{
        return ask1(k<<1,p,mid)+ask1(k<<1|1,mid+1,q);
    }
}
double ask2(int k,int p,int q)
{
    int l=tree[k].l,r=tree[k].r;
    if(l==p&&r==q)return tree[k].ssum;
    pushdown(k,r-l+1);
    int mid=(l+r)>>1;
    if(q<=mid)return ask2(k<<1,p,q);
    else if(p>mid)return ask2(k<<1|1,p,q);
    else{
        return ask2(k<<1,p,mid)+ask2(k<<1|1,mid+1,q);
    }
}
int main()
{
    scanf("%d%d",&n,&m);
    build(1,1,n);
    for(int i=0;i<m;i++){
        scanf("%d",&t);
        if(t==1){
            scanf("%d%d%lf",&x,&y,&z);
            change(1,x,y,z);
        }else if(t==2){
            scanf("%d%d",&x,&y);
            double ans=ask1(1,x,y)/(y-x+1);
            printf("%.4f\n",ans);
        }else{
            scanf("%d%d",&x,&y);
            double sum=ask1(1,x,y),ssum=ask2(1,x,y),ave=sum/(y-x+1);
            double ans=(ssum-2*ave*sum+(y-x+1)*ave*ave)/(y-x+1);
            printf("%.4f\n",ans);
        }
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值