区间方差

发布时间 2023-10-13 13:56:56作者: wscqwq

P5142 区间方差

单点修改,区间查询。

更新很简单,直接赋值,然后更新(注意 \(y^2\) 可能爆 int)。

对于询问,我们考虑完全平方公式 \((a_i-a)^2=a_i^2-2aa_i+a^2\),我们发现只需要维护区间平方和,区间和,平均数可以由区间和+逆元求出,然后就可以求了。

注意可能爆 int 的地方。

#include<cstdio>
#include<iostream>
using namespace std;
#define ls p<<1
#define rs p<<1|1
const int N=100010,M=4*N,mod=1e9+7;
int l[M],r[M],b[N],n,m,inv[N],ps[M],s[M];
typedef long long ll;
#define add(a,b) (a+=b)>=mod&&(a-=mod)
#define sub(a,b) (a-=b)<0&&(a+=mod)
#define up s[p]=s[ls],add(s[p],s[rs]),ps[p]=ps[ls],add(ps[p],ps[rs])
struct he{
    int ps,s;
    void operator+=(he A){
        add(ps,A.ps);
        add(s,A.s);
    }
    he(int _a=0,int _b=0):ps(_a),s(_b){}
};
void build(int p,int L,int R){
    l[p]=L,r[p]=R;
    if(L==R){
        s[p]=b[L],ps[p]=1ll*b[L]*b[L]%mod;
        return;
    }
    int mid=L+R>>1;
    build(ls,L,mid),build(rs,mid+1,R);
    up;
}
void update(int p,int x,int v){
    if(l[p]==r[p]){
        ps[p]=1ll*v*v%mod,s[p]=v;
        return;
    }
    int mid=l[p]+r[p]>>1;
    if(x<=mid)update(ls,x,v);
    else update(rs,x,v);
    up;
}
ll qpow(ll a,int b=mod-2){
    ll res=1;
    while(b){
        if(b&1)res=res*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return res;
}
he query(int p,int L,int R){
    if(L<=l[p]&&r[p]<=R)return he(s[p],ps[p]);
    int mid=l[p]+r[p]>>1;
    he ans;
    if(L<=mid)ans=query(ls,L,R);
    if(R>mid)ans+=query(rs,L,R);
    up;
    return ans;
}

int main(){
	#ifndef ONLINE_JUDGE
	freopen("1.in","r",stdin);
	#endif
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    cin>>n>>m;
    for(int i=1;i<=n;++i)cin>>b[i],inv[i]=i==1?1:1ll*(mod-mod/i)*inv[mod%i]%mod;
    build(1,1,n);
    for(int i=1;i<=m;++i){
        int op,x,y;
        ll len,in;
        cin>>op>>x>>y;
        in=inv[len=y-x+1];
        if(op==1)update(1,x,y);
        else{
            auto[h,pfh]=query(1,x,y);
            // cout<<h<<' '<<pfh<<'\n';
            ll p=h*in%mod;
            int ans=len*p%mod*p%mod;
            add(ans,pfh);
            sub(ans,p*h%mod*2%mod);
            ans=ans*in%mod;
            cout<<ans<<'\n';
            // cout<<p<<' '<<ans<<"\n\n";
        }
    }
    return 0;
}