P1471 方差
题目描述
蒟蒻HansBug在一本数学书里面发现了一个神奇的数列,包含N个实数。他想算算这个数列的平均数和方差。
借一下远航之曲大佬的图片,特别清晰:
那么只要维护区间平方和,就可以求方差了。
区间平方和,恩,push_down稍微改一下即可。
注意精度问题。
#include<bits/stdc++.h> #define N int(1e6) #define LL long long using namespace std; void in(LL &x) { register char c=getchar(); x=0; int f=1; while(!isdigit(c)) { if(c=='-') f=-1; c=getchar(); } while(isdigit(c)) { x=x*10+c-'0'; c=getchar(); } x*=f; } struct node{ LL l,r; double w1,w2,mul,ad; }tr[N]; inline void push_up(int k){ tr[k].w1=tr[k<<1].w1+tr[k<<1|1].w1; tr[k].w2=tr[k<<1].w2+tr[k<<1|1].w2; } inline void build(LL k,LL l,LL r){ tr[k].l=l,tr[k].r=r; if(l==r) { scanf("%lf",&tr[k].w1); tr[k].w2=tr[k].w1*tr[k].w1; return; } LL mid=(l+r)>>1; build(k<<1,l,mid); build(k<<1|1,mid+1,r); push_up(k); } inline void push_down(LL k){ if(tr[k].ad){ tr[k<<1].w2+=tr[k<<1].w1*2*tr[k].ad+(tr[k<<1].r-tr[k<<1].l+1)*tr[k].ad*tr[k].ad; tr[k<<1].w1+=tr[k].ad*(tr[k<<1].r-tr[k<<1].l+1); tr[k<<1].ad+=tr[k].ad; tr[k<<1|1].w2+=tr[k<<1|1].w1*2*tr[k].ad+(tr[k<<1|1].r-tr[k<<1|1].l+1)*tr[k].ad*tr[k].ad; tr[k<<1|1].w1+=tr[k].ad*(tr[k<<1|1].r-tr[k<<1|1].l+1); tr[k<<1|1].ad+=tr[k].ad; tr[k].ad=0; } } inline void update(LL k,LL L,LL R,double w){ int l=tr[k].l,r=tr[k].r,mid=(l+r)>>1; if(l>=L&&r<=R){ tr[k].w2+=tr[k].w1*2*w+(r-l+1)*w*w; tr[k].w1+=w*(r-l+1); tr[k].ad+=w; return; } push_down(k); if(L<=mid) update(k<<1,L,R,w); if(R>mid) update(k<<1|1,L,R,w); push_up(k); } double query1(LL k,LL L,LL R){ int l=tr[k].l,r=tr[k].r,mid=(l+r)>>1; if(l>=L&&r<=R) return tr[k].w1; push_down(k); double an=0; if(L<=mid) an+=query1(k<<1,L,R); if(R>mid) an+=query1(k<<1|1,L,R); push_up(k); return an; } double query2(LL k,LL L,LL R){ int l=tr[k].l,r=tr[k].r,mid=(l+r)>>1; if(l>=L&&r<=R) return tr[k].w2; push_down(k); double an=0; if(L<=mid) an+=query2(k<<1,L,R); if(R>mid) an+=query2(k<<1|1,L,R); push_up(k); return an; } LL n,m; int main() { in(n),in(m); build(1,1,n); for(LL opt,l,r,i=1;i<=m;i++){ in(opt),in(l),in(r); if(opt==1){ double w; scanf("%lf",&w); update(1,l,r,w); } if(opt==2){ printf("%.4lf ",(double)query1(1,l,r)/(r-l+1)); } if(opt==3){ double an=(double)query2(1,l,r)/(r-l+1)-(double)query1(1,l,r)/(r-l+1)*(double)query1(1,l,r)/(r-l+1); printf("%.4lf ",an); } } return 0; }