洛谷——P1471 方差

P1471 方差

题目描述

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

借一下远航之曲大佬的图片,特别清晰:

那么只要维护区间平方和,就可以求方差了。

区间平方和,恩,push_down稍微改一下即可。

注意精度问题。

#include<bits/stdc++.h>

#define N int(1e6)
#define LL long long

using namespace std;

void in(LL &x) {
    register char c=getchar();
    x=0;
    int f=1;
    while(!isdigit(c)) {
        if(c=='-') f=-1;
        c=getchar();
    }
    while(isdigit(c)) {
        x=x*10+c-'0';
        c=getchar();
    }
    x*=f;
}

struct node{
    LL l,r;
    double w1,w2,mul,ad;
}tr[N];

inline void push_up(int k){
    tr[k].w1=tr[k<<1].w1+tr[k<<1|1].w1;
    tr[k].w2=tr[k<<1].w2+tr[k<<1|1].w2;
}

inline void build(LL k,LL l,LL r){
    tr[k].l=l,tr[k].r=r;
    if(l==r) {
        scanf("%lf",&tr[k].w1);
        tr[k].w2=tr[k].w1*tr[k].w1;
        return;
    }
    LL mid=(l+r)>>1;
    build(k<<1,l,mid);
    build(k<<1|1,mid+1,r);
    push_up(k);
}

inline void push_down(LL k){
    if(tr[k].ad){
        tr[k<<1].w2+=tr[k<<1].w1*2*tr[k].ad+(tr[k<<1].r-tr[k<<1].l+1)*tr[k].ad*tr[k].ad;
        tr[k<<1].w1+=tr[k].ad*(tr[k<<1].r-tr[k<<1].l+1);
        tr[k<<1].ad+=tr[k].ad;
        tr[k<<1|1].w2+=tr[k<<1|1].w1*2*tr[k].ad+(tr[k<<1|1].r-tr[k<<1|1].l+1)*tr[k].ad*tr[k].ad;
        tr[k<<1|1].w1+=tr[k].ad*(tr[k<<1|1].r-tr[k<<1|1].l+1);
        tr[k<<1|1].ad+=tr[k].ad;
        tr[k].ad=0;
    }
}

inline void update(LL k,LL L,LL R,double w){
    int l=tr[k].l,r=tr[k].r,mid=(l+r)>>1;
    if(l>=L&&r<=R){
        tr[k].w2+=tr[k].w1*2*w+(r-l+1)*w*w;
        tr[k].w1+=w*(r-l+1);
        tr[k].ad+=w;
        return;
    }
    push_down(k);
    if(L<=mid) update(k<<1,L,R,w);
    if(R>mid) update(k<<1|1,L,R,w);
    push_up(k);
}

double query1(LL k,LL L,LL R){
    int l=tr[k].l,r=tr[k].r,mid=(l+r)>>1;
    if(l>=L&&r<=R) return tr[k].w1;
    push_down(k);
    double an=0; 
    if(L<=mid) an+=query1(k<<1,L,R);
    if(R>mid) an+=query1(k<<1|1,L,R);
    push_up(k);
    return an;
}

double query2(LL k,LL L,LL R){
    int l=tr[k].l,r=tr[k].r,mid=(l+r)>>1;
    if(l>=L&&r<=R) return tr[k].w2;
    push_down(k);
    double an=0; 
    if(L<=mid) an+=query2(k<<1,L,R);
    if(R>mid) an+=query2(k<<1|1,L,R);
    push_up(k);
    return an;
}

LL n,m;

int main()
{
    in(n),in(m);
    build(1,1,n);
    for(LL opt,l,r,i=1;i<=m;i++){
        in(opt),in(l),in(r);
        if(opt==1){
            double w;
            scanf("%lf",&w);
            update(1,l,r,w);
        }
        if(opt==2){
            printf("%.4lf\n",(double)query1(1,l,r)/(r-l+1));
        }
        if(opt==3){
            double an=(double)query2(1,l,r)/(r-l+1)-(double)query1(1,l,r)/(r-l+1)*(double)query1(1,l,r)/(r-l+1);
            printf("%.4lf\n",an);
        }
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/song-/p/9745876.html