洛谷 P5142 区间方差(线段树+数论)

 

 

关于求方差的题目之前做过,所以问题不算很难

和这道题目很像:https://baichuan.blog.csdn.net/article/details/110707826 

区别是这道题目要用逆元求解,利用费马小定理预处理出前 n 个数的逆元即可解决问题

const ll mod=1e9+7;
const int N=1e5+5;

    int i,j,k;
    int n,m;
    ll a[N];
    struct Node
    {
        int l,r;
        ll sum,sqr;
        #define lson id<<1
        #define rson id<<1|1
    }t[N<<2];
    ll ans,res,inv[N];
    
ll pow_mod(ll a,int x)
{
    ll ans=1;
    while(x){
        if(x&1) ans=ans*a%mod;
        a=a*a%mod;
        x>>=1;
    }
    return ans%mod;
}

void push_up(int id)
{
    t[id].sum=(t[lson].sum+t[rson].sum)%mod;
    t[id].sqr=(t[lson].sqr+t[rson].sqr)%mod;
}

void build(int l,int r,int id)
{
    t[id].l=l,t[id].r=r;
    if(l==r){
        t[id].sum=a[l];
        t[id].sqr=(a[l]*a[l])%mod;
    } else{
        int mid=l+r>>1;
        build(l,mid,lson);
        build(mid+1,r,rson);
        push_up(id);
    }
}

void update(int id,int pos,ll val)
{
    int L=t[id].l,R=t[id].r;
    if(L==R) t[id].sqr=val*val%mod,t[id].sum=val;
    else {
        int mid=L+R>>1;
        if(mid>=pos) update(lson,pos,val);
        else update(rson,pos,val);
        push_up(id);
    }
}

void query(int id,int l,int r)
{
    int L=t[id].l,R=t[id].r;
    if(L>=l && r>=R) res=(res+t[id].sum)%mod,ans=(ans+t[id].sqr)%mod;
    else {
        int mid=L+R>>1;
        if(mid>=l) query(lson,l,r);
        if(r>=mid+1) query(rson,l,r);
    }
}

int ask(int id,int x,int y)
{
    res=0,ans=0;
    query(id,x,y);
    res=res*inv[y-x+1]%mod; res=res*res%mod; 
    ans=ans*inv[y-x+1]%mod;
    return (ans-res+mod)%mod;
}

int main()
{
    //IOS;
    while(~sdd(n,m)){
        for(int i=1;i<=n;i++) inv[i]=pow_mod(i,mod-2);
        for(int i=1;i<=n;i++) sd(a[i]);
        build(1,n,1);
        int opt,x,y;
        while(m--){
            sddd(opt,x,y);
            if(opt==1) update(1,x,y);
            else pd(ask(1,x,y));
        }   
    }
    //PAUSE;
    return 0;
}

 

已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 酷酷鲨 设计师:CSDN官方博客 返回首页