IzumiSagiri
2018-11-15 19:29:26
我们可以设
那么我们就可以表示出方差了
至于修改也很简单了
于是就可以用带lazy的线段树来解决
丑陋的代码如下:
#include<cstdio>
#define ll long long
#define lc(x) (x<<1)
#define rc(x) (x<<1|1)
const ll maxn=100000;
double sum1[(maxn<<2)+5],sum2[(maxn)<<2+5];
double lazy[(maxn<<2)+5];
inline void pushup(ll v){
sum1[v]=sum1[lc(v)]+sum1[rc(v)];
sum2[v]=sum2[lc(v)]+sum2[rc(v)];
}
inline void pushdown(ll v,ll l,ll r){
if(lazy[v]){
ll mid=l+r>>1;
lazy[lc(v)]+=lazy[v];
lazy[rc(v)]+=lazy[v];
sum2[lc(v)]+=2.0*lazy[v]*sum1[lc(v)]+(mid-l+1)*lazy[v]*lazy[v];
sum2[rc(v)]+=2.0*lazy[v]*sum1[rc(v)]+(r-mid)*lazy[v]*lazy[v];
sum1[lc(v)]+=lazy[v]*(mid-l+1);
sum1[rc(v)]+=lazy[v]*(r-mid);
lazy[v]=0;
}
}
void update(ll v,ll l,ll r,ll left,ll right,double add){
if(left<=l&&r<=right){lazy[v]+=add,sum2[v]+=2.0*sum1[v]*add+(r-l+1)*add*add,sum1[v]+=add*(r-l+1);return;}
ll mid=l+r>>1;
pushdown(v,l,r);
if(left<=mid)update(lc(v),l,mid,left,right,add);
if(right>mid)update(rc(v),mid+1,r,left,right,add);
pushup(v);
}
double query_a(ll v,ll l,ll r,ll left,ll right){
if(left<=l&&r<=right){return sum1[v];}
ll mid=l+r>>1;double ans=0;
pushdown(v,l,r);
if(left<=mid)ans+=query_a(lc(v),l,mid,left,right);
if(right>mid)ans+=query_a(rc(v),mid+1,r,left,right);
return ans;
}
double query_b(ll v,ll l,ll r,ll left,ll right){
if(left<=l&&r<=right){return sum2[v];}
ll mid=l+r>>1;double ans=0;
pushdown(v,l,r);
if(left<=mid)ans+=query_b(lc(v),l,mid,left,right);
if(right>mid)ans+=query_b(rc(v),mid+1,r,left,right);
return ans;
}
ll n,m;
int main(){
scanf("%lld%lld",&n,&m);
for(ll i=1;i<=n;i++){
double p;scanf("%lf",&p);
update(1,1,n,i,i,p);
}
for(ll i=1;i<=m;i++){
ll op,l,r;scanf("%lld%lld%lld",&op,&l,&r);
if(op==1){
double k;scanf("%lf",&k);
update(1,1,n,l,r,k);
}
if(op==2){
double ans=(double)query_a(1,1,n,l,r)/(r-l+1);
printf("%.4lf\n",(double)ans);
}
if(op==3){
double ans=(double)query_a(1,1,n,l,r)/(r-l+1);
double ans1=(double)query_b(1,1,n,l,r)/(r-l+1);
double ans2=(double)ans1-(double)ans*ans;
printf("%.4lf\n",(double)ans2);
}
}
return 0;
}