又是线段树(维护方差)
发布日期:2022-02-22 18:04:13 浏览次数:9 分类:技术文章

本文共 1946 字,大约阅读时间需要 6 分钟。

我们把方差公式展开

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

当我们更新一个区间加时

所以pushdown就很好写了

具体见代码

 

#include
#include
#include
#include
#define int long longusing 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

  

转载于:https://www.cnblogs.com/eric-walker/p/9425022.html

转载地址:https://blog.csdn.net/dengxingrao0615/article/details/102231338 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:线段树区间取反
下一篇:线段树

发表评论

最新留言

第一次来,支持一个
[***.219.124.196]2024年04月15日 14时13分53秒