又是线段树(维护方差)

Posted eric-walker

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了又是线段树(维护方差)相关的知识,希望对你有一定的参考价值。

我们把方差公式展开

技术分享图片

所以只需要维护一个区间平方和和区间和

当我们更新一个区间加时

技术分享图片

所以pushdown就很好写了

具体见代码

 

#include<iostream>
#include<cstdio>
#include<cctype>
#include<cmath>
#define int long long
using namespace std;
#define ls(x) (x<<1)
#define rs(x) (ls(x)|1)
const int maxn=5e5+5;
struct FFF{
    int l,r;
    double sum;
	double sqr;
    double add;
    int mid(){return l+r>>1;}
    int len(){return r-l+1;}
	FFF(){l=r=0;sum=sqr=add=0;}
}t[maxn<<2];
int n,m;
void build(int l=1,int r=n,int o=1){
    t[o].l=l;t[o].r=r;
    t[o].add=0;
    if(l==r){
        scanf("%lf",&t[o].sum);
		t[o].sqr=pow(t[o].sum,2);
        return;
    }
    int mid=l+r>>1;
    build(l,mid,ls(o));
    build(mid+1,r,rs(o));
    t[o].sum=(t[ls(o)].sum+t[rs(o)].sum);
	t[o].sqr=(t[ls(o)].sqr+t[rs(o)].sqr);
}
void down(int o){
    double &v=t[o].add;
    for(int i=0;i<=1;++i){
	   t[ls(o)|i].sqr+=2*v*t[ls(o)|i].sum+t[ls(o)|i].len()*pow(v,2);
       t[ls(o)|i].sum+=t[ls(o)|i].len()*v;
	   t[ls(o)|i].add+=v;
    }
    v=0;
}
void add(int l,int r,double v,int o=1){
    if(l<=t[o].l&&t[o].r<=r){
		t[o].sqr+=2*v*t[o].sum+t[o].len()*pow(v,2);
		t[o].sum+=t[o].len()*v;
	   	t[o].add+=v;
        return;
    }
    int mid=t[o].mid();
    down(o);
    if(l<=mid)add(l,r,v,ls(o));
    if(r>mid)add(l,r,v,rs(o));
    t[o].sum=(t[ls(o)].sum+t[rs(o)].sum);
	t[o].sqr=(t[ls(o)].sqr+t[rs(o)].sqr);
}
double getsum(int l,int r,int o=1){
    if(l<=t[o].l&&t[o].r<=r){
        return t[o].sum;
    }
    double ans=0;
    int mid=t[o].mid();
    down(o);
    if(l<=mid)ans+=getsum(l,r,ls(o));
    if(r>mid)ans+=getsum(l,r,rs(o));
    return ans;
}
double getsqr(int l,int r,int o=1){
	if(l<=t[o].l&&t[o].r<=r){
        return t[o].sqr;
    }
    double ans=0;
    int mid=t[o].mid();
    down(o);
    if(l<=mid)ans+=getsqr(l,r,ls(o));
    if(r>mid)ans+=getsqr(l,r,rs(o));
    return ans;
}
signed main()
{
    cin>>n>>m;
    build();
    while(m--){
        int op,l,r;
		cin>>op>>l>>r;
		if(r<l)swap(l,r);
        if(op==1){
			double x;
			scanf("%lf",&x);
			add(l,r,x);
		}
		if(op==2){
			double sum=(double)getsum(l,r);
			printf("%.4lf
",sum/(r-l+1));
		}
		if(op==3){
			double sum=(double)getsum(l,r);
			double sqr=(double)getsqr(l,r);
			double len=(double)r-l+1;
			printf("%.4lf
",(-pow(sum/len,2)+(sqr)/len));
		}
    }
    return 0;
}

  

以上是关于又是线段树(维护方差)的主要内容,如果未能解决你的问题,请参考以下文章

Luogu P1471 方差

洛谷 P1471 方差

POJ1195-数据结构嵌套(二维线段树)

[luogu]P1471 方差

方差 线段树

[Luogu] 方差