线段树维护区间方差

线段树维护区间方差

方差

区间方差

还教室

  • 解题思路:
    利用线段树维护 \(a_i\)\(a_i^2 ( 1\leq i \leq n)\) 两个数列 ,然后使用一个 \(lazytag\) 来记录是否进行了区间加,最后输出方差的时候使用

    \[s^2 =\sum\limits_{i=1}^n (a_i-\overline a )^2 =\sum\limits_{i=1}^na_i^2+n\times\overline a^2-2 n\overline a^2=\sum\limits_{i=1}^na_i^2-n\overline a^2 \]

    就可以计算出区间方差
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 9;
#define int long long
int n, m;
class seg
{
public:
#define ls(p) (p << 1)
#define rs(p) (p << 1 | 1)

    struct node
    {
        int l, r;
        double tag;
        double sum, fsum; // 算术和与平方和
    };
    node t[maxn<<2];
    double a[maxn];
    void build(int p, int l, int r)
    {
        t[p].l = l, t[p].r = r;
        if (l == r)
        {
            t[p].sum = a[l];
            t[p].fsum = t[p].sum * t[p].sum;
            return;
        }
        int mid = l + r >> 1;
        build(ls(p), l, mid);
        build(rs(p), mid + 1, r);
        t[p].sum = t[ls(p)].sum + t[rs(p)].sum;
        t[p].fsum = t[ls(p)].fsum + t[rs(p)].fsum;
    }
    void pushdown(int p)
    {
        if (t[p].tag)
        {
            if(t[p].l!=t[p].r)
            {
                t[ls(p)].fsum+=(t[ls(p)].r-t[ls(p)].l+1)*t[p].tag*t[p].tag+2*t[p].tag*t[ls(p)].sum;
                t[rs(p)].fsum+=(t[rs(p)].r-t[rs(p)].l+1)*t[p].tag*t[p].tag+2*t[p].tag*t[rs(p)].sum;
                t[ls(p)].tag+=t[p].tag;
                t[rs(p)].tag+=t[p].tag;
                t[rs(p)].sum += (t[rs(p)].r - t[rs(p)].l + 1) * t[p].tag;
                t[ls(p)].sum += (t[ls(p)].r - t[ls(p)].l + 1) * t[p].tag;
                t[p].tag=0;
            }
            else
            {
                t[p].tag=0;
            }
        }
        
    }
    void change(int p, int l, int r,double x)
    {
        if(l<=t[p].l&&t[p].r<=r)
        {
            t[p].fsum+=(t[p].r-t[p].l+1)*x*x+2*x*t[p].sum;
            t[p].sum+=x*(t[p].r-t[p].l+1);
            t[p].tag+=x;
            return ;
        }
        if(t[p].r<l||t[p].l>r)return ;
        pushdown(p);
        int mid=t[p].l+t[p].r>>1;
        if(mid>=l)change(ls(p),l,r,x);
        if(mid<r) change(rs(p),l,r,x);
        t[p].sum = t[ls(p)].sum + t[rs(p)].sum;
        t[p].fsum = t[ls(p)].fsum + t[rs(p)].fsum;
    }
    double asksum(int p,int l,int r)
    {
        if(l<=t[p].l&&t[p].r<=r)
        {
            return t[p].sum;
        }
        if(t[p].r<l||t[p].l>r)return 0;
        double ans=0;
        pushdown(p);
        int mid=t[p].l+t[p].r>>1;
        if(mid>=l)ans+=asksum(ls(p),l,r);
        if(mid<r) ans+=asksum(rs(p),l,r);
        return ans;
    }
    double askfsum(int p,int l,int r)
    {
        if(l<=t[p].l&&t[p].r<=r)
        {
            return t[p].fsum;
        }
        if(t[p].r<l||t[p].l>r)return 0;
        double ans=0;
        pushdown(p);
        int mid=t[p].l+t[p].r>>1;
        if(mid>=l)ans+=askfsum(ls(p),l,r);
        if(mid<r) ans+=askfsum(rs(p),l,r);
        return ans;
    }
};
seg T;
signed main()
{
    std::ios::sync_with_stdio(0);
    std::cin.tie(0), cout.tie(0);
    cin >> n >> m;
    for (int i = 1; i <= n; i++)
    {
        cin >> T.a[i];
    }
    T.build(1,1,n);
    int t,x,y;
    double k;
    for(int i=1;i<=m;i++)
    {
        std::cin>>t;
        if(t==1)
        {
            cin>>x>>y;cin>>k;T.change(1,x,y,k);
        }
        else if(t==2)
        {
            std::cin>>x>>y;
            printf("%.4f\n",(double)T.asksum(1,x,y)*1.0/(1.0*(y-x+1)));
        }
        else 
        {
            cin>>x>>y;
            double t1=(double)T.asksum(1,x,y)/(y-x+1);
            double t2=(double)T.askfsum(1,x,y);
            printf("%.4f\n",(double)(t2-t1*t1*(y-x+1))/(y-x+1));
        }
    }
    return 0;
}
posted @ 2024-08-09 20:26  -风间琉璃-  阅读(1)  评论(0编辑  收藏  举报