首页 > 代码库 > 洛谷P1471 方差

洛谷P1471 方差

蒟蒻HansBug在一本数学书里面发现了一个神奇的数列,包含N个实数。他想算算这个数列的平均数和方差。

             ——by 洛谷;

http://www.luogu.org/problem/show?pid=1471

《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《

    平均数可以用线段树,维护区间和,直接维护平均数也行;

    然后对于方差;她有个公式的:

    S=[(a-Z)²+(b-Z)²+(c-Z)²+(d-Z)²+(e-Z)²...]/n(Z为平均数)

    S=[区间平方和-2*n*平均数²+n*平均数²]/n;

    S=[区间平方和-n*平均数²]/n;

    所以维护个平方和就好了;

    然后,平方和怎么区间加呢?

    她也有个公式:

    (a+z)²+(b+z)²+(c+z)²+(d+z)²+(e+z)²(你把她拆开嘛。。)

   =以前平方和+(2z*(Z*n)+n*z²);

然后是代码解释,

我只打了一个Lazy,意为在该区间的子树上要区间加,然后两个线段树共用;

代码如下:

  1 #include<cstdio>  2 #include<iostream>  3 using namespace std;  4 double treen[1000001];  5 double treen1[1000001];  6 double lz[1000001];  7 int n,m,R,L;  8 double a;  9  10 void build(int ,int ,int ); 11 void add(int ,int ,int ); 12 double sum( int ,int ,int ); 13 double sum1(int ,int ,int ); 14 void down(int ,int ,int ); 15  16 int main() 17 { 18     int i,j,b; 19     double ans,k; 20     scanf("%d%d",&n,&m); 21     build(1,n,1); 22     for(i=1;i<=m;i++) 23     { 24         scanf("%d",&b); 25         if(b==1) 26         { 27             scanf("%d%d",&L,&R); 28             cin>>a; 29             add(1,n,1); 30         } 31         if(b==2) 32         { 33             scanf("%d%d",&L,&R); 34             ans=sum(1,n,1)/(R-L+1); 35             printf("%.4lf\n",ans); 36         } 37         if(b==3) 38         { 39             scanf("%d%d",&L,&R); 40             ans=sum(1,n,1)/(R-L+1); 41             ans=ans*ans; 42             k=sum1(1,n,1); 43             ans=k/(R-L+1)-ans; 44             printf("%.4lf\n",ans); 45         } 46     } 47 } 48  49 void build(int l,int r,int nu) 50 { 51     if(l==r) 52     { 53         scanf("%lf",&treen[nu]); 54         treen1[nu]=treen[nu]*treen[nu]; 55         return ; 56     } 57     int mid=(l+r)>>1; 58     build(l,mid,nu<<1); 59     build(mid+1,r,(nu<<1)+1); 60     treen[nu]=(treen[nu<<1]*(mid-l+1)+treen[(nu<<1)+1]*(r-mid))/(r-l+1.0); 61     treen1[nu]=treen1[nu<<1]+treen1[(nu<<1)+1]; 62 } 63  64 void add(int l,int r,int nu) 65 { 66     if(L<=l&&r<=R) 67     { 68         lz[nu]+=a; 69         treen1[nu]+=(r-l+1)*(a*2*treen[nu]+a*a); 70         treen[nu]+=a; 71         return ; 72     } 73     int mid=(l+r)>>1; 74     down(l,r,nu); 75     if(L<=mid) 76         add(l,mid,nu<<1); 77     if(R>=mid+1) 78         add(mid+1,r,(nu<<1)+1); 79     treen[nu]=(treen[nu<<1]*(mid-l+1)+treen[(nu<<1)+1]*(r-mid))/(r-l+1.0); 80     treen1[nu]=treen1[nu<<1]+treen1[(nu<<1)+1]; 81 } 82  83 double sum(int l,int r,int nu) 84 { 85     double su=0; 86     if(L<=l&&r<=R) 87     { 88         return treen[nu]*(r-l+1); 89     } 90     int mid=(l+r)>>1; 91     down(l,r,nu); 92     if(L<=mid) 93         su+=sum(l,mid,nu<<1); 94     if(R>=mid+1) 95         su+=sum(mid+1,r,(nu<<1)+1); 96     return su; 97 } 98  99 double sum1(int l,int r,int nu)100 {101     double su=0;102     if(L<=l&&r<=R)103     {104         return treen1[nu];105     }106     int mid=(l+r)>>1;107     down(l,r,nu);108     if(L<=mid)109         su+=sum1(l,mid,nu<<1);110     if(R>=mid+1)111         su+=sum1(mid+1,r,(nu<<1)+1);112     return su;113 }114 115 void down(int l,int r,int nu)116 {117     int mid=(l+r)>>1;118     lz[nu<<1]+=lz[nu];119     lz[(nu<<1)+1]+=lz[nu];120     treen1[nu<<1]+=(mid-l+1)*(2*treen[nu<<1]*lz[nu]+lz[nu]*lz[nu]);121     treen1[(nu<<1)+1]+=(r-mid)*(2*treen[(nu<<1)+1]*lz[nu]+lz[nu]*lz[nu]);122     treen[nu<<1]+=lz[nu];123     treen[(nu<<1)+1]+=lz[nu];124     lz[nu]=0;125 }126 //5 5127 //1 1 1 1 1128 //1 2 2 -1129 //3 1 5

祝AC;

 

    

洛谷P1471 方差