• 洛谷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;
    }
    
  • 相关阅读:
    微软经典项目实例
    Extjs在vs中使用及弹出对话框的介绍
    微软企业库5.0学习笔记(七)
    微软企业库5.0学习笔记(八)
    微软企业库5.0学习笔记(十)
    .NET 4 并行(多核)编程系列之五
    NET 应用架构指导 V2[12]
    .NET 4 并行(多核)编程系列之四
    .NET 4 并行(多核)编程系列之三
    微软企业库5.0学习笔记(十二)
  • 原文地址:https://www.cnblogs.com/KnightL/p/14700879.html
Copyright © 2020-2023  润新知