线段树,方差,数学(Variance,玲珑杯 Round#5 H lonlife 1063)

以前只知道方差=(∑(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;
}


你可能感兴趣的:(期望,数学题,玲珑杯)