以前只知道方差=(∑(xi-x)^2)/n,1<=i<=n。x是平均数
没有办法用一棵线段树来维护方差。
现在知道了方差=Var[x] = E[x^2] - E[x]^2,就是平方的期望减去期望的平方。
所以用两颗线段树分别维护区间和与平方的区间和。然后算出答案就好了。
我们都知道,我们都知道,但我咋就不知道呢
以后要多打比赛,感觉打比赛收获很大。
代码
#include
#define ls (now<<1)
#define rs (ls|1)
using namespace std;
typedef long long ll;
const ll maxn=(1<<16)+10;
typedef pair pdd;
ll n,m;
ll a[maxn];
double tree1[maxn<<2];
double tree2[maxn<<2];
void up_data(ll now)
{
tree1[now]=tree1[ls]+tree1[rs];
tree2[now]=tree2[ls]+tree2[rs];
}
ll K;
void BUILD(ll l,ll r,ll now)
{
if(l==r)
{
tree1[now]=a[K];
tree2[now]=a[K]*a[K];
K++;
return;
}
ll m=(l+r)>>1;
BUILD(l,m,ls);
BUILD(m+1,r,rs);
up_data(now);
}
void A(ll l,ll r,ll now,ll pos,ll val)
{
if(l==r)
{
tree1[now]=val;
tree2[now]=val*val;
return;
}
ll m=(l+r)>>1;
if(pos<=m) A(l,m,ls,pos,val);
else A(m+1,r,rs,pos,val);
up_data(now);
}
pdd Q(ll l,ll r,ll now,ll ql,ll qr)
{
if(ql<=l&&r<=qr) return make_pair(tree1[now],tree2[now]);
ll m=(l+r)>>1;
pdd ansl=make_pair(0,0);
pdd ansr=make_pair(0,0);
if(ql<=m) ansl=Q(l,m,ls,ql,qr);
if(qr>m) ansr=Q(m+1,r,rs,ql,qr);
return make_pair(ansl.first+ansr.first,ansl.second+ansr.second);
}
int main()
{
while(scanf("%lld %lld",&n,&m)==2)
{
for(ll i=1;i<=n;i++)
scanf("%lld",&a[i]);
K=1;
BUILD(1,n,1);
ll x,y;
while(m--)
{
scanf("%lld",&x);
if(x==1)
{
scanf("%lld %lld",&x,&y);
A(1,n,1,x,y);
}
else
{
scanf("%lld %lld",&x,&y);
ll l=y-x+1;
pdd p=Q(1,n,1,x,y);
printf("%lld\n",ll(floor((p.second/l-(p.first*p.first/l/l))*l*l+0.5)));
}
}
}
return 0;
}