洛谷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 5 127 //1 1 1 1 1 128 //1 2 2 -1 129 //3 1 5
祝AC哟;
Just close your eyes, you`ll be alright, no one can hurt you after you die.