洛谷 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;
}
标签:洛谷,int,res,线段,mid,id,sqr,P5142,mod 来源: https://blog.csdn.net/C_Dreamy/article/details/111399972