zoukankan      html  css  js  c++  java
  • Luogu P1471 方差

    题目传送门

    开了十倍空间才过是什么鬼?该不会我线段树炸了吧……
    细思恐极


    平均数都会求,维护区间和,到时候除一下就好了。

    方差的求法如下
    (用的Luogu的图片)
    因为要维护一个平方,我们可以考虑使用van♂完全平方公式将它拆开,这样只用线段树维护区间和和区间平方和就可以了。
    对于区间修改,同样使用完全平方公式。

    要注意的一点是,修改时,要先修改平方和,再修改和,因为我们修改平方和时要用到区间和。

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    #define ls p<<1
    #define rs p<<1|1
    #define mid ((l+r)>>1)
    using namespace std;
    struct zzz{
    	double sum,pf;
    }tree[1000010<<2];
    double tag[1000010<<2],a[1000010];
    inline void up(int p){
    	tree[p].sum=tree[ls].sum+tree[rs].sum;
    	tree[p].pf=tree[ls].pf+tree[rs].pf;
    }
    void build(int l,int r,int p){
    	if(l==r){
    		tree[p].sum=a[l];
    		tree[p].pf=a[l]*a[l];
    		return ;
    	}
    	build(l,mid,ls); build(mid+1,r,rs);
    	up(p);
    }
    inline void down(int l,int r,int p){
    //用完全平方公式修改平方和
    	tree[ls].pf+=2*tree[ls].sum*tag[p]+tag[p]*tag[p]*(mid-l+1);
    	tree[rs].pf+=2*tree[rs].sum*tag[p]+tag[p]*tag[p]*(r-mid);
    //维护区间和
    	tree[ls].sum+=tag[p]*(mid-l+1);
    	tree[rs].sum+=tag[p]*(r-mid);
    	tag[ls]+=tag[p]; tag[rs]+=tag[p]; tag[p]=0;
    }
    void update(int l,int r,int p,int nl,int nr,double k){
    	if(l>=nl&&r<=nr){
    		tree[p].pf+=2*tree[p].sum*k+k*k*(r-l+1);
    		tree[p].sum+=k*(r-l+1);
    		tag[p]+=k;
    		return ;
    	}
    	down(l,r,p);
    	if(nl<=mid) update(l,mid,ls,nl,nr,k);
    	if(nr>mid) update(mid+1,r,rs,nl,nr,k);
    	up(p);
    }
    double query(int l,int r,int p,int nl,int nr){
    	double ans=0;
    	down(l,r,p);
    	if(l>=nl&&r<=nr) return tree[p].sum;
    	if(nl<=mid) ans+=query(l,mid,ls,nl,nr);
    	if(nr>mid) ans+=query(mid+1,r,rs,nl,nr);
    	return ans;
    }
    double query2(int l,int r,int p,int nl,int nr){
    	double ans=0;
    	down(l,r,p);
    	if(l>=nl&&r<=nr) return tree[p].pf;
    	if(nl<=mid) ans+=query2(l,mid,ls,nl,nr);
    	if(nr>mid) ans+=query2(mid+1,r,rs,nl,nr);
    	return ans;
    }
    int read(){
    	int k=0,f=1; char c=getchar();
    	for(;c<'0'||c>'9';c=getchar())
    	  if(c=='-') f=-1;
    	for(;c>='0'&&c<='9';c=getchar())
    	  k=k*10+c-48;
    	return k*f;
    }
    int main(){
    	int n=read(),m=read();
    	for(int i=1;i<=n;i++) scanf("%lf",&a[i]);
    	build(1,n,1);
    	for(int i=1;i<=m;i++){
    		int opt=read(),l=read(),r=read();
    		if(opt==1){
    			double k; scanf("%lf",&k);
    			update(1,n,1,l,r,k);
    		}
    		if(opt==2){
    			printf("%.4lf
    ",query(1,n,1,l,r)/(r-l+1));
    		}
    		if(opt==3){
    			double sum=query(1,n,1,l,r);
    			double pj=sum/(r-l+1);
    			double pf=query2(1,n,1,l,r);
    			printf("%.4lf
    ",(pf-2*sum*pj+pj*pj*(r-l+1))/(r-l+1));
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    C++中几个值得分析的小问题(1)
    《Effective C++》第5章 实现-读书笔记
    《Effective C++》第4章 设计与声明(2)-读书笔记
    《TCP/IP详解卷1:协议》第17、18章 TCP:传输控制协议(2)-读书笔记
    《Effective C++》第4章 设计与声明(1)-读书笔记
    《Effective C++》第3章 资源管理(2)-读书笔记
    【剑指Offer】24二叉树中和为某一值的路径
    【剑指Offer】23二叉搜索树的后序遍历序列
    【剑指Offer】22从上往下打印二叉树
    【剑指Offer】21栈的压入、弹出序列
  • 原文地址:https://www.cnblogs.com/morslin/p/11854924.html
Copyright © 2011-2022 走看看