Luogu P1471 方差

题目传送门

开了十倍空间才过是什么鬼?该不会我线段树炸了吧……
细思恐极


平均数都会求,维护区间和,到时候除一下就好了。

方差的求法如下
(用的Luogu的图片)
因为要维护一个平方,我们可以考虑使用van♂完全平方公式将它拆开,这样只用线段树维护区间和和区间平方和就可以了。
对于区间修改,同样使用完全平方公式。

要注意的一点是,修改时,要先修改平方和,再修改和,因为我们修改平方和时要用到区间和。

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#define ls p<<1
#define rs p<<1|1
#define mid ((l+r)>>1)
using namespace std;
struct zzz{
    double sum,pf;
}tree[1000010<<2];
double tag[1000010<<2],a[1000010];
inline void up(int p){
    tree[p].sum=tree[ls].sum+tree[rs].sum;
    tree[p].pf=tree[ls].pf+tree[rs].pf;
}
void build(int l,int r,int p){
    if(l==r){
        tree[p].sum=a[l];
        tree[p].pf=a[l]*a[l];
        return ;
    }
    build(l,mid,ls); build(mid+1,r,rs);
    up(p);
}
inline void down(int l,int r,int p){
//用完全平方公式修改平方和
    tree[ls].pf+=2*tree[ls].sum*tag[p]+tag[p]*tag[p]*(mid-l+1);
    tree[rs].pf+=2*tree[rs].sum*tag[p]+tag[p]*tag[p]*(r-mid);
//维护区间和
    tree[ls].sum+=tag[p]*(mid-l+1);
    tree[rs].sum+=tag[p]*(r-mid);
    tag[ls]+=tag[p]; tag[rs]+=tag[p]; tag[p]=0;
}
void update(int l,int r,int p,int nl,int nr,double k){
    if(l>=nl&&r<=nr){
        tree[p].pf+=2*tree[p].sum*k+k*k*(r-l+1);
        tree[p].sum+=k*(r-l+1);
        tag[p]+=k;
        return ;
    }
    down(l,r,p);
    if(nl<=mid) update(l,mid,ls,nl,nr,k);
    if(nr>mid) update(mid+1,r,rs,nl,nr,k);
    up(p);
}
double query(int l,int r,int p,int nl,int nr){
    double ans=0;
    down(l,r,p);
    if(l>=nl&&r<=nr) return tree[p].sum;
    if(nl<=mid) ans+=query(l,mid,ls,nl,nr);
    if(nr>mid) ans+=query(mid+1,r,rs,nl,nr);
    return ans;
}
double query2(int l,int r,int p,int nl,int nr){
    double ans=0;
    down(l,r,p);
    if(l>=nl&&r<=nr) return tree[p].pf;
    if(nl<=mid) ans+=query2(l,mid,ls,nl,nr);
    if(nr>mid) ans+=query2(mid+1,r,rs,nl,nr);
    return ans;
}
int read(){
    int k=0,f=1; char c=getchar();
    for(;c<'0'||c>'9';c=getchar())
      if(c=='-') f=-1;
    for(;c>='0'&&c<='9';c=getchar())
      k=k*10+c-48;
    return k*f;
}
int main(){
    int n=read(),m=read();
    for(int i=1;i<=n;i++) scanf("%lf",&a[i]);
    build(1,n,1);
    for(int i=1;i<=m;i++){
        int opt=read(),l=read(),r=read();
        if(opt==1){
            double k; scanf("%lf",&k);
            update(1,n,1,l,r,k);
        }
        if(opt==2){
            printf("%.4lf\n",query(1,n,1,l,r)/(r-l+1));
        }
        if(opt==3){
            double sum=query(1,n,1,l,r);
            double pj=sum/(r-l+1);
            double pf=query2(1,n,1,l,r);
            printf("%.4lf\n",(pf-2*sum*pj+pj*pj*(r-l+1))/(r-l+1));
        }
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/morslin/p/11854924.html