P1471 方差

原题链接  https://www.luogu.com.cn/problem/P1471

 

 

 

 

题解

我们先对题目中给出的求方差的式子进行化简:

 

我们需要维护区间和和区间平方和,因为平均数可以通过区间和得到;

看一下区间加 k 后方差有什么变化:

 

可以看到维护平方和的时候是要用到区间和的,所以我们应该先维护平方和再维护区间和。

还有就是注意要用 double !

Code:

#include<iostream>
#include<cstdio>
using namespace std;
int read()
{
    int a=0,x=1;
    char ch=getchar();
    while(ch<'0'||ch>'9')
    {
        if(ch=='-') x=-x;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9')
    {
        a=(a<<1)+(a<<3)+(ch-'0');
        ch=getchar();
    } 
    return a*x;
}
const int N=100005;
int n,m,oper;
double k,a[N],sum[N<<2],tag[N<<2],pfh[N<<2];   //sum:区间内所有数的和;pfh:区间内所有数的平方和 
void pushup(int node)                          //上传 
{
    sum[node]=sum[node<<1]+sum[node<<1|1];
    pfh[node]=pfh[node<<1]+pfh[node<<1|1];
}
void pushdown(int node,int l,int r)            //下传懒标记 
{
    int mid=(l+r)/2;
    double k=tag[node];
    pfh[node<<1]+=(mid-l+1)*k*k+2.0*k*sum[node<<1];     //注意平方和的优先级要更高 
    pfh[node<<1|1]+=(r-mid)*k*k+2.0*k*sum[node<<1|1];
    sum[node<<1]+=(mid-l+1)*k;                          //其次再算区间和 
    sum[node<<1|1]+=(r-mid)*k;
    tag[node<<1]+=k;
    tag[node<<1|1]+=k;
    tag[node]=0;
}
void build(int node,int l,int r)                //建树 
{
    if(l==r) 
    {
        sum[node]=a[l];
        pfh[node]=a[l]*a[l];
        return ;
    }
    int mid=(l+r)/2;
    build(node<<1,l,mid);
    build(node<<1|1,mid+1,r);
    pushup(node);
}
void add(int node,int l,int r,int x,int y,double k)
{
    if(x<=l&&r<=y)
    {
        pfh[node]+=(r-l+1)*k*k+2.0*k*sum[node];  //区间加k之后平方和的变化 
        sum[node]+=(r-l+1)*k; 
        tag[node]+=k;
        return ;
    }
    pushdown(node,l,r);
    int mid=(l+r)/2;
    if(x<=mid) add(node<<1,l,mid,x,y,k);
    if(y>mid) add(node<<1|1,mid+1,r,x,y,k);
    pushup(node);
}
double ask1(int node,int l,int r,int x,int y)    //询问区间和 
{
    if(x<=l&&r<=y) return sum[node];
    pushdown(node,l,r);
    int mid=(l+r)/2;
    double cnt=0;
    if(x<=mid) cnt+=ask1(node<<1,l,mid,x,y);
    if(y>mid) cnt+=ask1(node<<1|1,mid+1,r,x,y);
    return cnt;
}
double ask2(int node,int l,int r,int x,int y)    //询问区间平方和 
{
    if(x<=l&&r<=y) return pfh[node];
    pushdown(node,l,r);
    int mid=(l+r)/2;
    double cnt=0;
    if(x<=mid) cnt+=ask2(node<<1,l,mid,x,y);
    if(y>mid) cnt+=ask2(node<<1|1,mid+1,r,x,y);
    return cnt;
}
int main()
{
    n=read();m=read();
    for(int i=1;i<=n;i++) scanf("%lf",&a[i]);
    build(1,1,n);
    for(int i=1;i<=m;i++)
    {
        int x,y;
        oper=read();
        x=read();y=read();
        if(oper==1)
        {
            scanf("%lf",&k);
            add(1,1,n,x,y,k);     //区间[x,y]加上k 
        }
        if(oper==2)               
        {
            printf("%.4lf\n",ask1(1,1,n,x,y)/(y-x+1));  //询问[x,y]的平均数 
        }
        if(oper==3)
        {
            double a,b,c;
            a=ask2(1,1,n,x,y);    //区间平方和 
            c=(double)y-x+1;      //区间长度 
            b=ask1(1,1,n,x,y)/c;  //区间平均数          
            printf("%.4lf\n",a/c-b*b);   //询问[x,y]的方差 
        }
    }
    return 0;
}

 

  

posted @ 2020-05-31 10:39  暗い之殇  阅读(176)  评论(0编辑  收藏  举报