方差
方法同秦老师类似,就是维护一个平方和和一个区间和,注意数据类型一定是double
第一次写的时候写成ll结果全错了!!!
每次query要返回两个值,一个是平方和s2,一个是区间和s1,注意要先求s2,后求s1,
因为s2+=s1 * add *2+add * add * len(区间长度),s2中有s1,先求s1会使得求出来的额s2不是
正确的值!!!,用传引用&来返回s2,最后公式求一下就好啦
代码
#include<bits/stdc++.h>
using namespace std;
#define rd(x) scanf("%d",&x)
typedef long long ll;
const int N =1e5+10;
int n,m,opt;
double w[N];
struct node
{
int l,r;
double s1,s2;
double add;
}tr[N*4];
void pushup(int u)
{
tr[u].s1=tr[u<<1].s1+tr[u<<1|1].s1;
tr[u].s2=tr[u<<1].s2+tr[u<<1|1].s2;
}
void eval(node &u,double add)
{
u.s2+=u.s1*add*2+(u.r-u.l+1)*add*add;
u.s1+=(u.r-u.l+1)*add;
u.add+=add;
}
void pushdown(int u)
{
node &root=tr[u],&left=tr[u<<1],&right=tr[u<<1|1];
double &ad=tr[u].add;
if(ad)
{
eval(left,ad),eval(right,ad),ad=0;//传add
}
}
void build(int u,int l,int r)
{
if(l==r) tr[u]={r,r,w[r],w[r]*w[r]};
else
{
tr[u]={l,r};
int mid=l+r>>1;
build(u<<1,l,mid),build(u<<1|1,mid+1,r);
pushup(u);
}
}
void modify(int u,int l,int r,double add)
{
if(tr[u].l>=l&&tr[u].r<=r) eval(tr[u],add);
else
{
pushdown(u);
int mid=tr[u].l+tr[u].r>>1;
if(l<=mid) modify(u<<1,l,r,add);
if(r>mid) modify(u<<1|1,l,r,add);
pushup(u);
}
}
double query(int u,int l,int r,double &ans)
{
if(tr[u].l>=l&&tr[u].r<=r)
{
ans+=tr[u].s2;
return tr[u].s1;
}
else
{
pushdown(u);
double res=0;
int mid=tr[u].l+tr[u].r>>1;
if(l<=mid) res+=query(u<<1,l,r,ans);
if(r>mid) res+=query(u<<1|1,l,r,ans);
return res;
}
}
int main()
{
rd(n),rd(m);
for(int i=1;i<=n;i++) scanf("%lf",&w[i]);
build(1,1,n);
while(m--)
{
int l,r;
double c;
rd(opt),rd(l),rd(r);
if(opt==1) scanf("%lf",&c), modify(1,l,r,c);
else
{
double ans=0;
double res=query(1,l,r,ans);
if(opt==2) printf("%.4lf\n",res/(r-l+1));//求平均值
else printf("%.4lf\n",double(ans)/(r-l+1)-(double(res)/(r-l+1))*(double(res)/(r-l+1)));//求方差
}
}
}