洛谷P5142

本题化完简单式子然后直接上线段树即可。

Description

给定一个序列,对其进行单点修改和求区间方差的操作。

注意输出方差时要以分数取模形式输出。

Solution

单点修改不多说,来看求区间方差。

假设我们要求的是 ([x,y]) 的方差,也就是求:

[{frac{1}{y-x+1}sum_{i=x}^y}(a_i-overline a)^2 ]

化简以下(为了方便设 (d=y-x+1)):

({=frac{1}{d}sum_{i=x}^y(a_i^2-2a_ioverline a+overline a^2)})

({=frac{1}{d}[sum_{i=x}^y(a_i^2-2a_ioverline a)]+overline a^2})

({=frac{1}{d}sum_{i=x}^ya_i^2}-frac{1}{d}sum_{i=x}^ya_icdot 2overline a+overline a^2)

({=frac{1}{d}sum_{i=x}^ya_i^2}-2overline a^2+overline a^2)

({=frac{1}{d}sum_{i=x}^ya_i^2}-overline a^2)

所以根据推导过程可以看出,我们需要维护的是区间平方和以及区间和。

然后就上线段树板子,最后按上面的公式求值,分数换成逆元即可。

Code

#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#define maxn 510010
#define INF 0x3f3f3f3f
#define int long long
#define Mod 1000000007

using namespace std;

int n,m,a[maxn];

inline int read(){
    int s=0,w=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-') w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9')s=(s<<1)+(s<<3)+ch-'0',ch=getchar();
    return s*w;
}

int quickpow(int x,int y){
    int ans=1;
    while(y){
        if(y&1)ans=(ans*x)%Mod;
        x=(x*x)%Mod;y>>=1;
    }
    return ans;
}

namespace Seg{
    #define ls x<<1
    #define rs x<<1|1
    #define f(x) x*x%Mod
    int sum[maxn],fsum[maxn];
    
    void pushup(int x){
        sum[x]=(sum[ls]+sum[rs])%Mod;
        fsum[x]=(fsum[ls]+fsum[rs])%Mod;
    }
    
    void build(int x,int l,int r){
        if(l==r){
            sum[x]=a[l]%Mod;
            fsum[x]=f(a[l]);
            return;
        }
        int mid=l+r>>1;
        build(ls,l,mid);
        build(rs,mid+1,r);
        pushup(x);
    }
    
    void update(int x,int l,int r,int pos,int val){
        if(l==r){
            sum[x]=val%Mod;
            fsum[x]=f(val);
            return;
        }
        int mid=l+r>>1;
        if(pos<=mid) update(ls,l,mid,pos,val);
        else update(rs,mid+1,r,pos,val);
        pushup(x);
    } 
    
    int query(int x,int l,int r,int L,int R){
        int ans=0;
        if(L<=l&&R>=r) return sum[x]%Mod;
        int mid=l+r>>1;
        if(L<=mid) ans=(ans+query(ls,l,mid,L,R))%Mod;
        if(R>=mid+1) ans=(ans+query(rs,mid+1,r,L,R))%Mod;
        return ans%Mod;
    }
    
    int query2(int x,int l,int r,int L,int R){
        int ans=0;
        if(L<=l&&R>=r) return fsum[x]%Mod;
        int mid=l+r>>1;
        if(L<=mid) ans=(ans+query2(ls,l,mid,L,R))%Mod;
        if(R>=mid+1) ans=(ans+query2(rs,mid+1,r,L,R))%Mod;
        return ans%Mod;
    }   
    
    int query3(int x,int l,int r,int L,int R,int val){
        int ans=0;
        if(L<=l&&R>=r) return fsum[x]%Mod;
        int mid=l+r>>1;
        if(L<=mid) ans=(ans+query2(ls,l,mid,L,R))%Mod;
        if(R>=mid+1) ans=(ans+query2(rs,mid+1,r,L,R))%Mod;
        return ans%Mod;
    }
}

signed main(){
    n=read();m=read();
    for(int i=1;i<=n;i++) 
        a[i]=read();Seg::build(1,1,n);
    for(int i=1,opt,fir,sec;i<=m;i++){
        opt=read();fir=read();sec=read();
        if(opt==1) Seg::update(1,1,n,fir,sec);
        else{
            int ni=quickpow(sec-fir+1,Mod-2);
            int ave=Seg::query(1,1,n,fir,sec)*ni%Mod;
            int ans=Seg::query2(1,1,n,fir,sec)*ni%Mod-f(ave);
            printf("%lld
",(ans%Mod+Mod)%Mod);
        }
    }
    return 0;
}
原文地址:https://www.cnblogs.com/KnightL/p/14700879.html