LG-P1471 方差

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/xu0_zy/article/details/83719144

题目链接:https://www.luogu.org/problemnew/show/P1471

线段树的想法很明显,重点在于如何维护方差?

直接维护是不可能的,利用数学公式展开。

自己吧,反正展开后就是维护 区间和区间平方和

区间平方和如何pushdown?自己推吧,反正到最后是这个东西。
设 x 某子节点的左右边界为 L L R R ,区间和为 S S ,区间平方和为 S 2 S2
那么 S 2 + = x . l a z y × S × 2 + x . l a z y 2 × ( R L + 1 ) S2+=x.lazy×S×2+x.lazy^2×(R-L+1) 然后 S + = x . l a z y ( R L + 1 ) S+=x.lazy*(R-L+1)

最后询问方差的时候,设这个区间的元素个数为 k k ,区间和为 S 1 S1 ,平方和为 S 2 S2 ,输出 S 2 k S 1 2 k 2 \frac{S2}k-\frac{S1^2}{k^2}

#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=1e5+5,maxm=maxn;
typedef double DB;
int n,m;
DB a[maxn];
struct js{
	int L,R;
	DB s,s2,z;
}t[maxn<<2];
int rad()
{
	int ret=0,f=1;char ch=getchar();
	while (ch<'0'||ch>'9') {if (ch=='-') f=-1;ch=getchar();}
	while (ch>='0'&&ch<='9') ret=ret*10+ch-'0',ch=getchar();
	return ret*f;
}

DB sq(DB x){return x*x;}
void build(int x,int L,int R)
{
	t[x].L=L;t[x].R=R;
	if (L==R)
	{
		t[x].s=a[L];t[x].s2=a[L]*a[L];
		t[x].z=0;return;
	}
	int mid=L+R>>1;
	build(x<<1,L,mid);
	build(x<<1|1,mid+1,R);
	t[x].s=t[x<<1].s+t[x<<1|1].s;
	t[x].s2=t[x<<1].s2+t[x<<1|1].s2;
}
void pushdown(int x)
{
	if (t[x].z==0) return;
	DB L1=t[x<<1].R-t[x<<1].L+1,L2=t[x<<1|1].R-t[x<<1|1].L+1;
	t[x<<1].z+=t[x].z;
	t[x<<1|1].z+=t[x].z;
	t[x<<1].s2+=sq(t[x].z)*L1+2*t[x<<1].s*t[x].z;
	t[x<<1|1].s2+=sq(t[x].z)*L2+2*t[x<<1|1].s*t[x].z;
	t[x<<1].s+=t[x].z*L1;
	t[x<<1|1].s+=t[x].z*L2;
	t[x].z=0;
}
void put(int x,int le,int ri,DB dt)
{
	if (le>t[x].R||ri<t[x].L) return;
	if (le<=t[x].L&&t[x].R<=ri)
	{
		t[x].z+=dt;
		DB L=t[x].R-t[x].L+1;
		t[x].s2+=sq(dt)*L+t[x].s*dt*2;
		t[x].s+=dt*L;
		return;
	}
	pushdown(x);
	put(x<<1,le,ri,dt);
	put(x<<1|1,le,ri,dt);
	t[x].s=t[x<<1].s+t[x<<1|1].s;
	t[x].s2=t[x<<1].s2+t[x<<1|1].s2;
}
DB get1(int x,int le,int ri)
{
	if (le>t[x].R||ri<t[x].L) return 0;
	if (le<=t[x].L&&t[x].R<=ri) return t[x].s;
	pushdown(x);
	return get1(x<<1,le,ri)+get1(x<<1|1,le,ri);
}
DB get2(int x,int le,int ri)
{
	if (le>t[x].R||ri<t[x].L) return 0;
	if (le<=t[x].L&&t[x].R<=ri) return t[x].s2;
	pushdown(x);
	return get2(x<<1,le,ri)+get2(x<<1|1,le,ri);
}
int main()
{
	freopen("a2.in","r",stdin);freopen("a2.out","w",stdout);
	n=rad();m=rad();
	DB k,k1,k2;
	for (int i=1;i<=n;++i) scanf("%lf",a+i);
	build(1,1,n);
	for (int i=1,pd,x,y;i<=m&&(pd=rad(),x=rad(),y=rad(),true);++i)
	  switch (pd)
	  {
	  	  case 1:scanf("%lf",&k);put(1,x,y,k);break;
	  	  case 2:printf("%.4lf\n",get1(1,x,y)/(y-x+1));break;
	  	  case 3:{
	  	  		k=y-x+1;
	  	  		k1=get1(1,x,y)/k;
	  	  		k2=get2(1,x,y)/k;
	  	  		printf("%.4lf\n",k2-sq(k1));
				break;
			}
	  }
	return 0;
}

猜你喜欢

转载自blog.csdn.net/xu0_zy/article/details/83719144